/*****************************************************************************
 * This file contains functions for transaction state machine.
 *
*****************************************************************************/
#include <vector>
#include <math.h>
#include <algorithm>

#include <sys/time.h>
#include <string.h>
#include <cassert>
#include "cache.h"
#include "transaction.h"
#include "globals.h"
#include "sim_engine.h"
#include "pepsi_stats.h"
#include "pepsi_init.h"
#include "interface.h"

#define CORES numcpus 
#define NODES (num_llc_banks - 1)
#define DIRECTORY 1

extern int FLIT_WIDTH;
int temp_miss_count = 0;

void sim_result();
//long long count = 1000;
char string_tr[40][40]=  {"START",  "EXIT",  
                          "MLC_BUS_TRANSFER",
                          "MLC_QUEUED",
                          "MLC_LOOK_UP",
                          "LLC_BUS_TRANSFER",
                          "LLC_ICN_OVERFLOW",
                          "LLC_ICN_QUEUED",
                          "LLC_ICN_TRANSFER",
                          "LLC_QUEUED",
                          "LLC_LOOK_UP",
                          "MEM_QUEUED",
                          "MEM_BUS_TRANSFER",
                          "SNOOP_BLOCKED",
                          "LLC_BLOCKED_QUEUE_HEAD",
                          "LLC_REPLACE_SM",
                          "MLC_RESPONSE_TRANSFER",
                          "MLC_BLOCKED_HEAD_QUEUE",
                          "MLC_REPLACE_SM",
                          "MLC_RSM_LLC_TRANSFER",
                          "MLC_RSM_LLC_LOOKUP",
                          "LLC_RSM_LLC_LOOKUP",
                          "LLC_MSHR_PENDING",
                          "MLC_MSHR_PENDING",
                          "LLC_RSM_LOOKUP_COMPLETE",
                          "MLC_BQ_OVERFLOW",
                          "LLC_BQ_OVERFLOW",
                          "MEM_ICN_TRANSFER",
                          "MEM_ICN_OVERFLOW",
                          "REQUEST",
                          "RESPONSE",
                          "L1_REQUEST",
                          "L2_REQUEST",
                          "L1_RESPONSE",
                          "L2_RESPONSE",
                          "MEM_ACCESS"
                         };

int DBG_TRID = -1;


void determine_new_tr_event(TRANSTYPE *tr)
{

    if(tr->tr_id == DBG_TRID)
        DEBUG = 1;

    if((tr->active_cp && strstr(tr->active_cp->clabel,"LLC") && tr->cache < CORES) || tr->cache < 0)
    {
        printf("\n\n  Tr Cache : %d :::  CORES : %d\n", tr->cache, CORES);
        printf("ERR Tr->cache low for LLC caches\n");
        tr->hist();
    }

    switch(tr->type)
    {
    case READ :
    {
        /* STATE MACHINE FOR READS */
        switch(tr->state)
        {
        case START :
        {
            tr->prev_state = tr->state;
            tr->state = MLC_BUS_TRANSFER;
            tr->cache = tr->cpuid;
            tr->active_cp = &(clevel[MLC].cache[tr->cache]);
            tr->timestamp += core_transfer_time;
            break;
        }

        case EXIT :
        {
            if(tr->prev_state == MLC_RSM_LLC_TRANSFER || tr->prev_state == MLC_RSM_LLC_LOOKUP
                    || tr->prev_state == MLC_RESPONSE_TRANSFER ||tr->prev_state == MLC_BLOCKED_HEAD_QUEUE )
            {
                if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                    if(DEBUG) printf("ERROR in deleteing from queue while exiting\n");
                tr->active_cp->delete_blocked_queue(tr->tr_id);
                int bindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid):tr->cpuid;
                clevel[LLC].cache[bindex].delete_blocked_queue(tr->tr_id);
            }

            if(tr->prev_state == SNOOP_BLOCKED)
                tr->active_cp->delete_blocked_queue(tr->tr_id);
            break;
        }

        case MLC_BUS_TRANSFER :
        {
            tr->mem_queue_wait = 0;
            if(tr->active_cp->queue_empty())
            {
                tr->prev_state = tr->state;
                tr->state = MLC_LOOK_UP;
                //Measure Response time removing the trace blocking
                tr->enter_time = global_clock - core_transfer_time;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;
            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = MLC_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->mlcq_enter = tr->timestamp;
                tr->timestamp = BLOCKED;
            }
            break;
        }
        case MLC_QUEUED :
        {
            if( tr->tr_id == tr->active_cp->queue_head())
            {
                tr->mlc_queue_wait += global_clock - tr->mlcq_enter;
                if(DEBUG)
                    printf("TRANSACTION : MLC QUEUE WAIT :%ld\n for TR:%ld", tr->mlc_queue_wait, tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = MLC_LOOK_UP;
                //Measure Response time removing the trace blocking
                tr->enter_time = global_clock - core_transfer_time;

                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                tr->timestamp = global_clock + mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;
            }
            break;
        }
        case MLC_LOOK_UP :
        {
            if(!tr->bq_delete)
            {
                if(!tr->mlc_bq_overflow)
                {
                    tr->active_cp->refs++;
                    tr->active_cp->refs_per_core[tr->cpuid]++;
                    tr->active_cp->reads++;
                }
                else
                    tr->mlc_bq_overflow = false;
            }

            if(tr->cstate != INVALID)
            {
                if(tr->bq_delete)
                    tr->bq_delete = false;

                tr->prev_state = tr->state;
                tr->state = EXIT;
                if (tr->active_cp->delete_queue_tr(tr->tr_id)!= tr->tr_id)
                    if(DEBUG) printf("ERROR: Deleting from MLC queue\n");

                tr->active_cp->delete_blocked_queue(tr->tr_id);

                tr->timestamp += core_transfer_time;
                tr->mlc_queue_wait = 0;

                transaction_commit(tr);

            }
            else
            {
                if(tr->active_cp->blocked_queue_full() && !tr->bq_delete)
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_BQ_OVERFLOW;
                    tr->mlcq_enter = tr->timestamp;
                    tr->timestamp = BLOCKED;
                    tr->mlc_bq_overflow = true;
                    break;
                }

                if(tr->bq_delete)
                    tr->bq_delete = false;
                /* Assuming 32 bit address, first  bit determine which LLC address
                ** is mapped to */
                int cacheindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid;

                //printf("\n TR--Address : %lld ", tr->address);



                if (tr->active_cp->delete_queue_tr(tr->tr_id)!= tr->tr_id)
                    if(DEBUG) printf("ERROR: Deleting from MLC queue\n");

                if(!tr->active_cp->insert_blocked_queue(tr->tr_id))
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_MSHR_PENDING;
                    tr->mlcq_enter = tr->timestamp;
                    tr->timestamp = BLOCKED;
                }
                else
                {
                    tr->active_cp->misses++;
                    tr->active_cp->misses_per_core[tr->cpuid]++;

                    processor[tr->tid].l1misses++;
                    processor[tr->tid].bank_touch[cacheindex]++;
                    processor[tr->tid].per_flow_packets[cacheindex]++;
                    //tr->slack = processor[tr->tid].returnSlackPriority(tr->rob_entry,false);
                    processor[tr->tid].rob_array[tr->rob_entry].l1miss = 1;
                    processor[tr->tid].current_outstanding_packets++;

                    //  tr->active_cp->misses_per_pri[tr->pri]++;

                    //Inserting L1 Prefetcher.
                    //long long trid = tr->tr_id;
                    // IssueL1Prefetches(global_clock,  tr->tr_id);
                    //Re-map tr
                    //tr = map_transaction(trid);



                    tr->prev_state = tr->state;
                    tr->state = LLC_ICN_OVERFLOW;

                    tr->llc_transfer_state = LLC_BUS_TRANSFER;
                    tr->active_cp = &(clevel[LLC].cache[cacheindex]);
                    //tr->src = tr->cache;
                    tr->src = cpu_network_layout[tr->cpuid];
                    tr->msg_size = CADDR_SIZE;
                    addr_msgs++;
                    tr->dst = cache_network_layout[cacheindex];
                    tr->timestamp += llc_transfer_time;

                    if(RECORD_NOC && tr->cache != cacheindex)
                        gzprintf(rec_noc_fp,"DRQ   %d %d 4 %lld\n",tr->cache, cacheindex, global_clock);

                    tr->cache = CORES + cacheindex;

                }
            }
            break;
        }

        case MLC_MSHR_PENDING :
        {
            if(tr->mshr_pending[MLC])
            {
                if(DEBUG)
                    printf("TRANSACTION : MLC QUEUE WAIT :%ld for TR :%lld\n", tr->mlc_queue_wait, tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = MLC_QUEUED;
                tr->active_cp->insert_queue_after_head(tr->tr_id);
                tr->mshr_pending[MLC] = false;
                tr->bq_delete = true;
            }
            break;
        }

        case MLC_BQ_OVERFLOW :
        {
            if(!tr->active_cp->blocked_queue_full())
            {
                if(DEBUG)
                    printf("TRANSACTION : MLC BQ QUEUE OVERFLOW for TR :%lld\n", tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = MLC_QUEUED;
                // tr->mlc_bq_overflow = false;
            }
            break;
        }

        case LLC_ICN_OVERFLOW :
        {
            if(SHORT_CIRCUIT)
            {
                tr->state = tr->llc_transfer_state;
                tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                tr->prev_state = LLC_ICN_OVERFLOW;
                //csim_inj_msgs++;
            }
            else
            {
                if(icn_func_sim[tr->tid])
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    per_core_icn_lat[tr->tid] += SHORT_CIRCUIT_ICN_LAT;
                    per_core_icn_msgs[tr->tid] ++;
                    break;
                }

                if(tr->src == tr->dst)
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock + 1;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                }
                else if(nic_queue_full(tr->src))
                    tr->timestamp = BLOCKED;
                else
                {
                    tr->icn_trans_comp = false;
                    tr->msg_inj_time = global_clock;
                    tr->timestamp = BLOCKED;
                    insert_nic_queue(tr->src, tr->dst, tr->msg_size, global_clock, tr->tr_id);
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    tr->state = LLC_ICN_TRANSFER;
                }
            }
            break;
        }

        case LLC_ICN_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                total_icn_msgs++;
                total_icn_latency += global_clock - tr->msg_inj_time;
                per_core_icn_lat[tr->tid] += global_clock - tr->msg_inj_time;
                per_core_icn_msgs[tr->tid] ++;

                tr->icn_trans_comp = false;
                tr->timestamp = global_clock + 1;
                tr->prev_state = LLC_ICN_TRANSFER;
                tr->state = tr->llc_transfer_state;
            }
            break;
        }

        case MEM_ICN_OVERFLOW :
        {

            if(MEM_SHORT_CIRCUIT)
            {
                tr->state = tr->mem_transfer_state;
                tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                tr->prev_state = MEM_ICN_OVERFLOW;
                //csim_inj_msgs++;
            }
            else
            {
                if(icn_func_sim[tr->tid])
                {
                    tr->state = tr->mem_transfer_state;
                    tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                    tr->prev_state = MEM_ICN_OVERFLOW;
                    per_core_icn_lat[tr->tid] += SHORT_CIRCUIT_ICN_LAT;
                    per_core_icn_msgs[tr->tid] ++;
                    break;
                }


                if(tr->src == tr->dst)
                {
                    tr->state = tr->mem_transfer_state;
                    tr->timestamp = global_clock + 1;
                    tr->prev_state = MEM_ICN_OVERFLOW;
                }
                else if(nic_queue_full(tr->src))
                {
                    tr->timestamp = BLOCKED;
                }
                else
                {
                    tr->icn_trans_comp = false;
                    tr->msg_inj_time = global_clock;
                    //tr->timestamp = BLOCKED;
                    insert_nic_queue(tr->src, tr->dst, tr->msg_size, global_clock, tr->tr_id);
                    tr->prev_state = MEM_ICN_OVERFLOW;
                    tr->state = MEM_ICN_TRANSFER;
                }
            }
            break;
        }


        case MEM_ICN_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                total_icn_msgs++;
                total_icn_latency += global_clock - tr->msg_inj_time;
                per_core_icn_lat[tr->tid] += global_clock - tr->msg_inj_time;
                per_core_icn_msgs[tr->tid] ++;

                tr->icn_trans_comp = false;
                tr->timestamp = global_clock + 1;
                tr->prev_state = MEM_ICN_TRANSFER;
                tr->state = tr->mem_transfer_state;
            }
            break;
        }

        case LLC_BUS_TRANSFER :
        {
            if(tr->active_cp->queue_full())
            {
                tr->timestamp = BLOCKED;
            }
            else if(tr->active_cp->queue_empty())
            {
                tr->prev_state = tr->state;
                tr->state = LLC_LOOK_UP;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                tr->timestamp = global_clock + llc_lookup_time;

            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = LLC_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->llcq_enter = global_clock;
                tr->timestamp = BLOCKED;
            }
            break;
        }

        case LLC_QUEUED :
        {
            if( tr->tr_id == tr->active_cp->queue_head())
            {
                tr->llc_queue_wait += global_clock - tr->llcq_enter;
                tr->prev_state = tr->state;
                tr->state = LLC_LOOK_UP;
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                tr->timestamp = global_clock + llc_lookup_time;
                llc_busy_time += llc_lookup_time;
            }
            break;
        }

        case LLC_LOOK_UP :
        {
            if(!tr->bq_delete)
            {
                if(!tr->llc_bq_overflow)
                {
                    //printf("LLC COUNT %d\t",tr->tr_id);
                    if(tr->cstate == INVALID /*|| tr->cstate == SHARED*/)
                    {
                        tr->active_cp->refs++;
                        tr->active_cp->refs_per_core[tr->cpuid]++;
                        //tr->active_cp->refs_per_pri[tr->pri]++;
                    }
                    else
                    {
                        tr->active_cp->refs++;
                        tr->active_cp->refs_per_core[tr->cpuid]++;
                        //tr->active_cp->refs_per_pri[tr->pri]++;
                    }
                    if(tr->cstate == SHARED)
                        tr->active_cp->shared_hits++;
                    tr->active_cp->reads++;
                }
                else
                    tr->llc_bq_overflow=false;

                if(tr->cstate != SHARED &&
                        tr->active_cp->blocked_queue_full())
                {
                    tr->prev_state = tr->state;
                    tr->state = LLC_BQ_OVERFLOW;
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                    tr->llc_bq_overflow = true;
                    break;
                }

            }
            else
            {
                tr->bq_delete = false;
            }

            //if(tr->cstate != INVALID)
            //tr->active_cp->prefetched_hit_check(tr->address,tr);

            // if(LLC_PREFETCH_BUFFER)
            // {
            // vector<long long>::iterator it;
            // it = find(tr->active_cp->prefetch_buffer.begin(), tr->active_cp->prefetch_buffer.end(), address);
            // if ( it != tr->active_cp->prefetch_buffer.end())
            // {	// Address found in the HLC prefetch_buffer

            // LLC_PB_hit++;		// increment the prefetch hit statistics
            // tr->active_cp->prefetch_buffer.erase(it);		//remove from the prefetch buffer, as it's hit once.
            // }
            //now, proceed as usual to insert that address into the HLC cache.
            // }


            if(tr->call_issue_prefetches == false)
            {
                int curr_trid = tr->tr_id;
                if(tr->cstate != INVALID)
                {
                    tr->l2hit = 1;
                    tr->l2miss = 0;
                }
                else
                {
                    tr->l2hit = 0;
                    tr->l2miss = 1;
                }

                IssuePrefetches(global_clock, tr->tr_id);


                //If the tr_pool was rearranged by the OS to a different location, then re-map.
                if(tr->tr_id != curr_trid)
                    tr = map_transaction(curr_trid);

                tr->call_issue_prefetches = true;

                //#printf("\n\n\n\n\n MISSED_ADDRESS : %lld\n\n\n\n", tr->address);
            }



            if(tr->cstate == SHARED)
            {
                /* Assuming 32 bit address, first  bit determine which LLC address
                ** is mapped to */
                int cacheindex = tr->cpuid;

                tr->active_cp->change_state(tr->address, SHARED,tr);
                tr->active_cp->delete_queue_tr(tr->tr_id);

                tr->active_cp->delete_blocked_queue(tr->tr_id);

                tr->mlc_state = SHARED;

                tr->active_cp = &(clevel[MLC].cache[cacheindex]);
                tr->prev_state = tr->state;
                //tr->print();
                //tr->hist();
                tr->state = LLC_ICN_OVERFLOW;
                tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
                tr->src = cache_network_layout[tr->cache - CORES];
                tr->msg_size = CLINE_SIZE;
                data_msgs++;
                //printf("imsg size : %d, %d\n",tr->msg_size, tr->linesize);
                //tr->dst = cacheindex;
                tr->dst = cpu_network_layout[tr->cpuid];
                tr->timestamp += llc_transfer_time;
                if(RECORD_NOC && tr->src != tr->dst)
                    gzprintf(rec_noc_fp,"DRSP  %d %d 64 %lld\n",tr->src,tr->dst, global_clock);
                tr->cache = cacheindex;


            }
            else if(tr->cstate == EXCLUSIVE)
            {
                TRANSTYPE *tr_snoop[CORES];
                if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                    if(DEBUG) printf("ERROR: In deleting from Queue while blocking for snoop\n" );

                if(!tr->active_cp->insert_blocked_queue(tr->tr_id))
                {
                    tr->prev_state = tr->state;
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                    tr->state = LLC_MSHR_PENDING;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = SNOOP_BLOCKED;
                    tr->snoopq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                    long long trid = tr->tr_id;
                    for (int i =0,j =0; i < CORES  ; i++)
                    {
                        tr->snoop_done[i] = FALSE;
                        if(i == tr->cpuid)
                            continue;
#if DIRECTORY
                        if(clevel[MLC].cache[i].look_up(tr->address,false,tr) == INVALID)
                            continue;
#endif
                        int curr_trid = tr->tr_id;
                        tr_pool.push_back(TRANSTYPE());

                        /* STL migh relocate vectors after psushing and element
                    ** thus this might cause dangling pointers */
                        if(curr_trid != tr->tr_id)
                            tr = map_transaction(curr_trid);

                        tr_snoop[j] = &(tr_pool.back());
                        tr_snoop[j]->state = START;
                        tr_snoop[j]->tr_id = transaction_count++;
                        tr_snoop[j]->address = tr->address;
                        tr_snoop[j]->type = SNOOP;
                        tr_snoop[j]->parent = tr->tr_id;
                        tr_snoop[j]->cache = i;
                        tr_snoop[j]->timestamp = global_clock;
                        tr_snoop[j]->enter_time = global_clock;
                        tr_snoop[j]->cpuid = i;
                        tr_snoop[j]->tid = tr->tid;
                        tr_snoop[j]->active_cp = &(clevel[MLC].cache[i]);
                        j++;
                        tr->snoop_count = j;
                    }
                    if(DEBUG)
                    {
                        printf("sending out snoops for %d with snoop_count : %d [%p %p]\n",tr->tr_id,tr->snoop_count,tr,map_transaction(tr->tr_id));
                    }
                }
            }
            else if(tr->cstate == MODIFIED)
            {
                int cacheindex = tr->cpuid;

                tr->active_cp->writebacks++;

                tr->active_cp->change_state(tr->address, EXCLUSIVE, tr);
                tr->active_cp->delete_queue_tr(tr->tr_id);
                tr->active_cp->delete_blocked_queue(tr->tr_id);

                tr->mlc_state = EXCLUSIVE;

                tr->active_cp = &(clevel[MLC].cache[cacheindex]);
                tr->prev_state = tr->state;
                tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
                tr->state = LLC_ICN_OVERFLOW;

                tr->src = cache_network_layout[tr->cache - CORES];
                //tr->dst = cacheindex;
                tr->dst = cpu_network_layout[tr->cpuid];
                tr->msg_size = CLINE_SIZE;
                data_msgs++;
                // printf("imsg size : %d, %d\n",tr->msg_size, tr->linesize);
                tr->timestamp += llc_transfer_time;
                if(RECORD_NOC && tr->src != tr->dst)
                    gzprintf(rec_noc_fp,"DRSP  %d %d 64 %lld\n",tr->src, tr->dst, global_clock);
                tr->cache = cacheindex;
                /* Do we need to writeback this block to memory now ? */
                TRANSTYPE *tr_mem;
                long long trid = tr->tr_id;
                tr_pool.push_back(TRANSTYPE());
                /* STL migh relocate vectors after psushing and element
                ** thus this might cause dangling pointers */
                if(trid != tr->tr_id)
                    tr = map_transaction(trid);
                

                tr_mem = &(tr_pool.back());
                tr_mem->tr_id = transaction_count++;
                tr_mem->address = tr->address;
                tr_mem->type = WRITEBACK;
                tr_mem->cache = MEM;
                //tr_mem->timestamp = global_clock + mem_transfer_time;
                tr_mem->memq_enter = global_clock;

                if(DRAMSIM_MEMORY)
                {
                    //Inserting into the memory considering the mem controller id.
                    //mem->addDRAMTransaction(isWrite, addr);
                    uint64_t physical_address;
                    physical_address = tr_mem->address;
                    //printf("\n TRID:%d :: Insert WRITE at %lld ; ADDR : %0x%1x",tr_mem->tr_id, global_clock,physical_address);

                    int mem_ctr_id = DECODE_MEM_CTRLR(tr_mem->address, tr_mem->cpuid);

                    if(mem_ctr_id == 0)
                        mem1->addDRAMTransaction(true, physical_address);
                    else if(mem_ctr_id == 1)
                        mem2->addDRAMTransaction(true, physical_address);
                    else if(mem_ctr_id == 2)
                        mem3->addDRAMTransaction(true, physical_address);
                    else if(mem_ctr_id == 3)
                        mem4->addDRAMTransaction(true, physical_address);
                    tr_mem->timestamp = global_clock+9999;
                }
                else
                {
                    tr_mem->timestamp = global_clock + mem_transfer_time;
                }


                tr_mem->enter_time = global_clock;
                tr_mem->cpuid = tr->cpuid;
                tr_mem->tid = tr->tid;
                tr_mem->active_cp = MEMORY;
                tr_mem->prev_state = LLC_LOOK_UP;
                tr_mem->state = MEM_BUS_TRANSFER;
            }
            else if(tr->cstate == INVALID)
            {

                if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                    if(DEBUG)  printf("ERROR: In deleting from Queue while blocking for memory\n" );

                if(!tr->active_cp->insert_blocked_queue(tr->tr_id))
                {
                    tr->prev_state = tr->state;
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                    tr->state = LLC_MSHR_PENDING;
                }
                else
                {
                    /*  An LLC Miss has happened  */
                    tr->llc_memq_miss = true;
                    tr->active_cp->misses++;
                    tr->active_cp->misses_per_core[tr->cpuid]++;
                    processor[tr->tid].l2misses++;
                    processor[tr->tid].rob_array[tr->rob_entry].l2miss = 1;


                    /* Nachi -Up5*/
                    /* The function that decides if prefetch is to be issued. It determines the next address to be prefetched. */
                    //long long trid = tr->tr_id;
                    //IssuePrefetches(global_clock,  tr->tr_id);
                    //Re-map tr
                    //tr = map_transaction(trid);

                    tr->active_cp = MEMORY;
                    int mem_ctr_id = DECODE_MEM_CTRLR(tr->address, tr->cpuid);
                    tr->memq_enter = global_clock;
                    if(DRAMSIM_MEMORY)
                    {
                        //Inserting into the memory considering the mem controller id.
                        //mem->addDRAMTransaction(isWrite, addr);
                        uint64_t physical_address;
                        physical_address = tr->address;
                        //printf("\n TRID:%d :: Insert READ at %lld ; ADDR : %0x%1x",tr->tr_id, global_clock,physical_address);



                        if(mem_ctr_id == 0)
                            mem1->addDRAMTransaction(false, physical_address);
                        else if(mem_ctr_id == 1)
                            mem2->addDRAMTransaction(false, physical_address);
                        else if(mem_ctr_id == 2)
                            mem3->addDRAMTransaction(false, physical_address);
                        else if(mem_ctr_id == 3)
                            mem4->addDRAMTransaction(false, physical_address);
                        tr->timestamp = global_clock+9999;
                        //So that the system does not fail. We are modeling a DRAM model approximately.
                        //In the worst case, atleast in 999 cycles, the data is returned. // Due to time contraints, its is done.
                        //Has been verified, even if 9999999 is replaced with 999, it works fine. So why 999 ? So that simulator does not run into max long number problems (it goes into -ve some times and transaction is processed right away!).
                    }
                    else
                    {
                        tr->timestamp = global_clock + mem_transfer_time;
                    }
                    tr->prev_state = tr->state ;

                    int cacheindex = DECODE_BANK(tr->address, tr->cpuid);
                    tr->state = MEM_ICN_OVERFLOW;
                    tr->mem_transfer_state = MEM_BUS_TRANSFER;
                    tr->src = cache_network_layout[cacheindex];
                    tr->dst = mem_network_layout[mem_ctr_id];
                    tr->msg_size = CADDR_SIZE;
                    addr_msgs++;


                    // printf("\n trid: %d  :: LLC Miss at time : %d:: Timestamp = %d :: Address :0x%lx", tr->tr_id, global_clock, tr->timestamp, tr->address);

                    tr->cache = MEM;
                    tr->llc_state = EXCLUSIVE;
                    tr->mlc_state = EXCLUSIVE;
                }
            }
            break;
        }

        case LLC_MSHR_PENDING :
        {
            if(tr->mshr_pending[LLC])
            {
                tr->prev_state = tr->state;
                tr->state = LLC_QUEUED;
                tr->active_cp->insert_queue_after_head(tr->tr_id);
                tr->mshr_pending[LLC] = false;
                tr->bq_delete = true;
            }

            break;
        }
        case LLC_BQ_OVERFLOW :
        {
            if(!tr->active_cp->blocked_queue_full())
            {
                if(DEBUG)
                    printf("TRANSACTION : LLC BQ QUEUE OVERFLOW for TR :%lld\n", tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = LLC_QUEUED;
                //tr->llc_bq_overflow = false;
            }
            else
            {
                if(tr->active_cp->queue.size() > 1)
                {
                    TRANSTYPE *tmp = map_transaction(tr->active_cp->queue[1]);
                    if(tmp->from_blocked_queue == true)
                    {
                        tr->active_cp->delete_queue_tr(tr->tr_id);
                        std::vector<long long>::iterator start = tr->active_cp->queue.begin();
                        start++;
                        tr->active_cp->queue.insert(start, tr->tr_id);
                    }
                }
            }
            break;
        }

        case MEM_BUS_TRANSFER :
        {

            if(tr->active_cp->queue_full())
            {
                if(DEBUG)
                    printf("MEM QUEUE FULL\n");
                tr->timestamp = BLOCKED;
            }
            else if(tr->active_cp->queue_empty())
            {
                tr->llc_first = TRUE;
                tr->cache = CORES + (llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid);
                tr->active_cp =
                        &(clevel[LLC].cache[llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid]);
                //printf("tr->cache %d\n",tr->cache);
                tr->prev_state = MEM_QUEUED;

                int mem_ctr_id = DECODE_MEM_CTRLR(tr->address, tr->cpuid);
                int cacheindex = DECODE_BANK(tr->address, tr->cpuid);
                tr->state = MEM_ICN_OVERFLOW;
                tr->mem_transfer_state = LLC_BLOCKED_QUEUE_HEAD;
                tr->dst = cache_network_layout[cacheindex];
                tr->src = mem_network_layout[mem_ctr_id];
                tr->msg_size = CLINE_SIZE;
                data_msgs++;
                tr->timestamp = global_clock + memory_access_time;
            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = MEM_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->timestamp = BLOCKED;
            }
            break;
        }
        case MEM_QUEUED :
        {
            if(tr->tr_id == tr->active_cp->queue_head())
            {
                tr->active_cp->delete_queue();
                tr->timestamp = global_clock + memory_access_time;

                tr->llc_first = TRUE;
                tr->state = LLC_BLOCKED_QUEUE_HEAD;
                tr->active_cp =
                        &(clevel[LLC].cache[llc_shared ? DECODE_BANK(tr->address, tr->cpuid):tr->cpuid]);
                tr->cache = CORES + (llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid);

                tr->prev_state = MEM_QUEUED;
            }
            break;

        }

        case SNOOP_BLOCKED :
        {
            int done = FALSE, count=0;
            int snoop_state = INVALID ;
            for(int i = 0; i< CORES ; i++)
                if( tr->snoop_done[i] == TRUE)
                    count++;


            if(DEBUG)
            {
                printf("in SNOOP BLOCKED count %d snoop_count %d id:%lld timestamp:%lld tmp-count %d %p %p\n",count,tr->snoop_count,tr->tr_id,tr->timestamp,tr,map_transaction(tr->tr_id));
            }

            if(count == tr->snoop_count/* && tr->prev_state == LLC_REPLACE_SM*/)
            {
                done = TRUE;
                /*for(int i = 0; i< CORES ; i++)
                  tr->snoop_done[i] = FALSE;*/
            }
            /*
                 else if(count == CORES - 1 && tr->snoop_invalidate== FALSE)
                 {
                 done = TRUE;
                 for(int i = 0; i< CORES ; i++)
                 tr->snoop_done[i] = FALSE;
                 if(DEBUG) printf("in SNOOP BLOCKED count %d\n",count);
                 }
                 else if(count == CORES && tr->snoop_invalidate== TRUE)
                 {
                 done = TRUE;
                 for(int i = 0; i< CORES ; i++)
                 tr->snoop_done[i] = FALSE;
                 if(DEBUG) printf("in SNOOP BLOCKED count %d\n",count);
                 }*/

            if(done)
            {
                tr->snoop_wait += global_clock - tr->snoopq_enter;
                for(int i =0; i<CORES ; i++)
                {
                    if(!tr->snoop_done[i])
                        continue;
                    tr->snoop_done[i] = FALSE;
                    if( tr->snoop_state[i] == MODIFIED)
                    {
                        tr->active_cp->writebacks++;
                        long long trid = tr->tr_id;
                        if(tr->snoop_invalidate == FALSE)
                        {
                            if( i!= tr->cpuid)
                            {
                                TRANSTYPE *tr_mem;
                                snoop_state = MODIFIED;
                                if(DEBUG) printf("SNOOP FOR TR %d resulted in MODIFIED ", tr->tr_id);

                                int curr_trid = tr->tr_id;
                                tr_pool.push_back(TRANSTYPE());
                                /* STL migh relocate vectors after psushing and element
                        ** thus this might cause dangling pointers */

                                if(curr_trid != tr->tr_id)
                                    tr = map_transaction(curr_trid);

                                tr_mem = &(tr_pool.back());
                                tr_mem->tr_id = transaction_count++;
                                tr_mem->address = tr->address;
                                tr_mem->type = WRITEBACK;
                                tr_mem->cache = MEM;
                                //tr_mem->timestamp = global_clock + mem_transfer_time;
                                tr_mem->memq_enter = global_clock;
                                if(DRAMSIM_MEMORY)
                                {
                                    //Inserting into the memory considering the mem controller id.
                                    //mem->addDRAMTransaction(isWrite, addr);
                                    uint64_t physical_address;
                                    physical_address = tr_mem->address;
                                    //printf("\n TRID:%d :: Insert WRITE at %lld ; ADDR : %0x%1x",tr_mem->tr_id, global_clock,physical_address);

                                    int mem_ctr_id = DECODE_MEM_CTRLR(tr_mem->address, tr_mem->cpuid);

                                    if(mem_ctr_id == 0)
                                        mem1->addDRAMTransaction(true, physical_address);
                                    else if(mem_ctr_id == 1)
                                        mem2->addDRAMTransaction(true, physical_address);
                                    else if(mem_ctr_id == 2)
                                        mem3->addDRAMTransaction(true, physical_address);
                                    else if(mem_ctr_id == 3)
                                        mem4->addDRAMTransaction(true, physical_address);
                                    tr_mem->timestamp = global_clock+9999;
                                }
                                else
                                {
                                    tr_mem->timestamp = global_clock + mem_transfer_time;
                                }

                                tr_mem->enter_time = global_clock;
                                tr_mem->cpuid = tr->cpuid;
                                tr_mem->tid = tr->tid;
                                tr_mem->active_cp = MEMORY;
                                tr_mem->prev_state = tr->state;
                                tr_mem->state = MEM_BUS_TRANSFER;
                            }
                        }
                        else
                        {
                            tr->active_cp = MEMORY;
                            //tr->timestamp = global_clock + mem_transfer_time;
                            tr->memq_enter = global_clock;
                            if(DRAMSIM_MEMORY)
                            {

                                //Inserting into the memory considering the mem controller id.
                                //mem->addDRAMTransaction(isWrite, addr);
                                uint64_t physical_address;
                                physical_address = tr->address;
                                //printf("\n TRID:%d :: Insert WRITE at %lld ; ADDR : %0x%1x",tr->tr_id, global_clock,physical_address);

                                int mem_ctr_id = DECODE_MEM_CTRLR(tr->address, tr->cpuid);

                                if(mem_ctr_id == 0)
                                    mem1->addDRAMTransaction(true, physical_address);
                                else if(mem_ctr_id == 1)
                                    mem2->addDRAMTransaction(true, physical_address);
                                else if(mem_ctr_id == 2)
                                    mem3->addDRAMTransaction(true, physical_address);
                                else if(mem_ctr_id == 3)
                                    mem4->addDRAMTransaction(true, physical_address);
                                tr->timestamp = global_clock+9999;
                            }
                            else
                            {
                                tr->timestamp = global_clock + mem_transfer_time;
                            }
                            tr->prev_state = tr->state;
                            tr->type = WRITEBACK;
                            tr->state = MEM_BUS_TRANSFER;
                        }

                        snoop_state = MODIFIED;
                        if(DEBUG) printf("SNOOP FOR TR %d resulted in MODIFIED", tr->tr_id);
                        break;
                    }
                    if( /*i!= tr->cpuid &&*/ tr->snoop_state[i] == SHARED)
                    {
                        snoop_state = SHARED;
                        if(DEBUG) printf("SNOOP FOR TR %d resulted in SHARED", tr->tr_id);
                        break;
                    }
                    if( /*i!= tr->cpuid &&*/ tr->snoop_state[i] == EXCLUSIVE)
                    {
                        snoop_state = EXCLUSIVE;
                        if(DEBUG) printf("SNOOP FOR TR %d resulted in EXCLUSIVE", tr->tr_id);
                        break;
                    }

                }/* END of FOR */

                if(tr->snoop_invalidate == FALSE)
                {
                    int cacheindex = tr->cpuid;

                    tr->active_cp->change_state(tr->address, SHARED,tr);

                    tr->mlc_state = SHARED;

                    tr->active_cp = &(clevel[MLC].cache[cacheindex]);
                    tr->prev_state = tr->state;
                    tr->state = LLC_ICN_OVERFLOW;
                    tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
                    tr->src = cache_network_layout[tr->cache - CORES];
                    //tr->dst = cacheindex;
                    tr->dst = cpu_network_layout[tr->cpuid];
                    tr->msg_size = CLINE_SIZE;
                    data_msgs++;
                    //printf("imsg size : %d, %d\n",tr->msg_size, tr->linesize);
                    /* APPROXIMATION for block update time */
                    tr->timestamp = global_clock + llc_lookup_time + llc_transfer_time;
                    if(RECORD_NOC && tr->src != tr->dst)
                        gzprintf(rec_noc_fp,"DRSP  %d %d 64 %lld\n",tr->src,tr->dst, global_clock);
                    llc_busy_time += llc_lookup_time;
                    tr->cache = cacheindex;
                }
                else
                {
                    if(snoop_state != MODIFIED)
                    {
                        tr->prev_state = tr->state;
                        tr->state = EXIT;
                        tr->timestamp = global_clock + llc_lookup_time;
                        llc_busy_time += llc_lookup_time;
                    }
                }

            }/* End of Done */

            break;
        }

        case LLC_BLOCKED_QUEUE_HEAD :
        {

            if(tr->llc_first)
            {
                //MEMORY->delete_queue_tr(tr->tr_id);
                if(DEBUG)
                {
                    if(tr->llc_memq_miss != true)
                    {
                        printf("ERR\n");
                        tr->hist();
                    }
                    else

                        temp_miss_count++;

                    int llc_misses=0;
                    for(int i=0; i<num_llc_banks; i++)
                        llc_misses += clevel[LLC].cache[i].misses;
                    printf("mem latency %d : llc misses %d;  temp_miss_count %d id %d\n", global_clock - tr->memq_enter, llc_misses, temp_miss_count, tr->tr_id);

                    if(tr->history[tr->history.size() - 3].state != LLC_LOOK_UP)
                    {
                        printf("ERR\n");
                        tr->hist();
                    }
                }
                tr->active_cp->insert_queue_after_head(tr->tr_id);
                tr->llc_first = FALSE;
                if(tr->tr_id == tr->active_cp->queue_head())
                {
                    tr->prev_state = tr->state;
                    tr->state = LLC_REPLACE_SM;
                }
                else
                {
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                }

            }
            else
            {
                int head = tr->active_cp->queue_head();

                TRANSTYPE *head_tr = map_transaction(head);
                if(head_tr->state == LLC_BQ_OVERFLOW )
                {
                    tr->active_cp->queue.erase(tr->active_cp->queue.begin());
                    tr->active_cp->rq_size--;
                    tr->active_cp->insert_queue_after_head(head);
                }


                if(tr->tr_id == tr->active_cp->queue_head())
                {
                    tr->llc_queue_wait += global_clock - tr->llcq_enter;
                    tr->prev_state = tr->state;
                    tr->state = LLC_REPLACE_SM;
                }
            }

            break;
        }

        case LLC_REPLACE_SM :
        {

            /* Assumption victim lookup time inclusive of update time for the
              ** victim with new block from memory and done at same time */

            std::vector<long long> vaddr;

            tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, &vaddr, tr->llc_state, tr);

            tr->timestamp = global_clock + llc_victim_lookup_time + llc_lookup_time;

            llc_busy_time += llc_victim_lookup_time;
            llc_busy_time += llc_lookup_time;

            int vindex = 0;

            if(vaddr.size()== 0)
            {
                tr->prev_state = tr->state;
                tr->state = LLC_RSM_LOOKUP_COMPLETE;
            }

            while(vindex < vaddr.size())
            {
                if(DEBUG)
                    printf("Examining vindex %d vaddr %llx in LLC_REPLACE_SM : READ\n");

                tr->vaddress = vaddr[vindex];
                vindex++;

                if(tr->vaddress != tr->address)
                    tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);
                else
                    tr->vstate = INVALID;
                tr->prev_state = tr->state;
                if(INVALID == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    //tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos, tr->pri);
                    tr->state = LLC_RSM_LOOKUP_COMPLETE;
                }
                else if(MODIFIED == tr->vstate)
                {
                    TRANSTYPE *tr_mem;
                    tr->active_cp->writebacks++;
                    long long trid = tr->tr_id;


                    tr_pool.push_back(TRANSTYPE());

                    /* STL migh relocate vectors after psushing and element
                  ** thus this might cause dangling pointers */

                    if(trid != tr->tr_id)
                        tr = map_transaction(trid);


                    tr_mem = &(tr_pool.back());
                    tr_mem->tr_id = transaction_count++;
                    tr_mem->address = tr->address;
                    tr_mem->type = WRITEBACK;
                    tr_mem->cache = MEM;
                    tr_mem->memq_enter = global_clock;
                    if(DRAMSIM_MEMORY)
                    {
                        //tr_mem->timestamp = global_clock + mem_transfer_time;
                        //Inserting into the memory considering the mem controller id.
                        //mem->addDRAMTransaction(isWrite, addr);
                        uint64_t physical_address;
                        physical_address = tr_mem->address;
                        //printf("\n TRID:%d :: Insert WRITE at %lld ; ADDR : %0x%1x",tr_mem->tr_id, global_clock,physical_address);

                        int mem_ctr_id = DECODE_MEM_CTRLR(tr_mem->address, tr_mem->cpuid);

                        if(mem_ctr_id == 0)
                            mem1->addDRAMTransaction(true, physical_address);
                        else if(mem_ctr_id == 1)
                            mem2->addDRAMTransaction(true, physical_address);
                        else if(mem_ctr_id == 2)
                            mem3->addDRAMTransaction(true, physical_address);
                        else if(mem_ctr_id == 3)
                            mem4->addDRAMTransaction(true, physical_address);
                        tr_mem->timestamp = global_clock+9999;
                    }
                    else
                    {
                        tr_mem->timestamp = global_clock + mem_transfer_time;
                    }

                    tr_mem->enter_time = global_clock;
                    tr_mem->cpuid = tr->cpuid;
                    tr_mem->tid = tr->tid;
                    tr_mem->active_cp = MEMORY;
                    tr_mem->prev_state = tr->state;
                    tr_mem->state = MEM_BUS_TRANSFER;

                    tr->prev_state = tr->state;
                    tr->state = LLC_RSM_LOOKUP_COMPLETE;
                    //tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos, tr->pri);
                }
                else if(EXCLUSIVE == tr->vstate || SHARED == tr->vstate )
                {
                    TRANSTYPE *tr_new;
                    TRANSTYPE *tr_snoop[CORES];
                    long long trid = tr->tr_id;

                    tr_pool.push_back(TRANSTYPE());
                    /* STL migh relocate vectors after psushing and element
                  ** thus this might cause dangling pointers */

                    if(trid != tr->tr_id)
                        tr = map_transaction(trid);

                    tr_new = &(tr_pool.back());
                    tr_new->copy(*tr);
                    tr_new->tr_id = transaction_count++;
                    tr_new->address = tr->vaddress;
                    tr_new->snoop_invalidate = TRUE;
                    //if(!tr_new->active_cp->insert_blocked_queue(tr_new->tr_id))
                    // {
                    // if(DEBUG)
                    // printf("FATAL ERR REPL LLC!!! Inside MSHR LLC RSM case:%lld, new:%lld vaddres %llx\n",tr->tr_id,tr_new->tr_id, tr->vaddress);
                    //DEBUG=1;
                    /* tr->prev_state = tr->state;
                     tr->active_cp->look_up(tr->vaddress,TRUE);
                     tr->state = LLC_REPLACE_SM;
                     tr->timestamp = global_clock;
                     tr_pool.pop_back();
                     tr_new->active_cp->delete_blocked_queue(tr_new->tr_id);
                  //getchar();
                  break;*/
                    //}
                    // else
                    {
                        //  tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos, tr->pri);
                        tr_new->prev_state = tr->state;
                        tr_new->state = SNOOP_BLOCKED;
                        tr_new->timestamp = BLOCKED;
                        long long trid = tr->tr_id;

                        for (int i =0,j =0; i < CORES  ; i++)
                        {
                            tr_new->snoop_done[i] = FALSE;
                            //  if(i == tr_new->cpuid)
                            // continue;
#if DIRECTORY
                            if(clevel[MLC].cache[i].look_up(tr_new->address,false,tr) == INVALID)
                                continue;
#endif
                            tr_pool.push_back(TRANSTYPE());
                            /* STL migh relocate vectors after psushing and element
                      ** thus this might cause dangling pointers */
                            if(trid != tr->tr_id)
                                tr = map_transaction(trid);

                            tr_snoop[j] = &(tr_pool.back());
                            tr_snoop[j]->tr_id = transaction_count++;
                            tr_snoop[j]->state = START;
                            tr_snoop[j]->address = tr_new->address;
                            tr_snoop[j]->type = SNOOP;
                            tr_snoop[j]->parent = tr_new->tr_id;
                            tr_snoop[j]->cache = i;
                            tr_snoop[j]->timestamp = global_clock;
                            tr_snoop[j]->enter_time = global_clock;
                            tr_snoop[j]->cpuid = i;
                            tr_snoop[j]->tid = tr_new->tid;
                            tr_snoop[j]->active_cp = &(clevel[MLC].cache[i]);
                            j++;
                            tr_new->snoop_count = j;
                        }
                        tr->prev_state = tr->state;
                        tr->state = LLC_RSM_LOOKUP_COMPLETE;
                    }
                }
            }

            break;
        }
        case LLC_RSM_LOOKUP_COMPLETE:
        {
            int cacheindex = tr->cpuid;
            //tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos);
            tr->active_cp->delete_blocked_queue(tr->tr_id);
            if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                if(DEBUG) printf("ERROR: In deleting from Queue while LLC REPLACEMENT\n" );

            tr->active_cp = &(clevel[MLC].cache[cacheindex]);
            tr->prev_state = tr->state;
            tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
            tr->state = LLC_ICN_OVERFLOW;
            tr->src = cache_network_layout[tr->cache - CORES];
            tr->msg_size = CLINE_SIZE;
            data_msgs++;
            // printf("imsg size : %d, %d\n",tr->msg_size, tr->linesize);
            //tr->dst = cacheindex;
            tr->dst = cpu_network_layout[tr->cpuid];
            tr->timestamp +=  llc_transfer_time;

            if(RECORD_NOC && tr->src != tr->dst)
                gzprintf(rec_noc_fp,"DRSP  %d %d 64 %lld\n",tr->src, tr->dst, global_clock);
            tr->cache = cacheindex;


            break;
        }

            /* STATE MACHINE for MLC REPLACEMENT begins here */
        case MLC_RESPONSE_TRANSFER :
        {
            tr->active_cp->insert_queue_after_head(tr->tr_id);
            if(tr->active_cp->queue_head() == tr->tr_id)
            {

                tr->timestamp += core_transfer_time ;
                transaction_commit(tr);

                tr->timestamp -= (core_transfer_time);

                tr->vaddress = tr->active_cp->victim_lookup(tr->address, &tr->rep_pos,NULL, INVALID, tr);
                if(tr->vaddress != tr->address)
                    tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);
                else tr->vstate = INVALID;
                tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->mlc_state,tr->rep_pos,
                                              tr);

                //if(l1prefetch_enable == 1)
                //if(tr->prefetch_transaction == 1)
                //tr->active_cp->prefetched_bit_set(tr->address,tr);

                tr->timestamp += mlc_victim_lookup_time;
                tr->timestamp += mlc_lookup_time;


                mlc_busy_time += mlc_victim_lookup_time;
                mlc_busy_time += mlc_lookup_time;

                if(INVALID == tr->vstate || SHARED == tr->vstate || EXCLUSIVE == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_REPLACE_SM;
                }
            }
            else
            {
                tr->timestamp = BLOCKED;
                tr->prev_state = tr->state;
                tr->state = MLC_BLOCKED_HEAD_QUEUE;
            }
            break;
        }
        case MLC_BLOCKED_HEAD_QUEUE:
        {
            int head = tr->active_cp->queue_head();

            TRANSTYPE *head_tr = map_transaction(head);
            if(head_tr->state == MLC_BQ_OVERFLOW )
            {
                tr->active_cp->queue.erase(tr->active_cp->queue.begin());
                tr->active_cp->rq_size--;
                tr->active_cp->insert_queue_after_head(head);
            }


            if(tr->active_cp->queue_head() == tr->tr_id)
            {
                tr->timestamp = global_clock + core_transfer_time;
                transaction_commit(tr);



                tr->vaddress = tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, NULL, INVALID, tr);
                tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->mlc_state,tr->rep_pos, tr);
                tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);

                tr->timestamp = global_clock + mlc_victim_lookup_time;
                mlc_busy_time += mlc_victim_lookup_time;
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;

                if(INVALID == tr->vstate || SHARED == tr->vstate || EXCLUSIVE == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_REPLACE_SM;
                }
            }

            break;
        }
        case MLC_REPLACE_SM :
        {
            int cacheindex =llc_shared ? DECODE_BANK(tr->vaddress, tr->cpuid) : tr->cpuid;

            int bindex =llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid;
            clevel[LLC].cache[bindex].delete_blocked_queue(tr->tr_id);

            tr->active_cp->delete_blocked_queue(tr->tr_id);
            tr->active_cp->delete_queue_tr(tr->tr_id);

            tr->active_cp = &(clevel[LLC].cache[cacheindex]);
            tr->prev_state = tr->state;
            tr->llc_transfer_state = MLC_RSM_LLC_TRANSFER;
            tr->state = LLC_ICN_OVERFLOW;
            //tr->src = tr->cache;
            tr->src = cpu_network_layout[tr->cpuid];
            tr->dst = cache_network_layout[cacheindex];
            tr->msg_size = (fetch_csize(tr->vdata)*SET_SEG_SIZE)/FLIT_SIZE_BYTES + CADDR_SIZE;
            wb_msgs++;
            if(RECORD_NOC && tr->cache != cacheindex)
                gzprintf(rec_noc_fp,"WBX   %d %d 64 %lld\n",tr->cache,cacheindex, global_clock);
            tr->cache = cacheindex + CORES;
            break;
        }

        case MLC_RSM_LLC_TRANSFER :
        {
            if(EXCLUSIVE == tr->vstate)
                //tr->llc_state = INVALID;
                tr->llc_state = EXCLUSIVE;
            else if(MODIFIED == tr->vstate)
                tr->llc_state = MODIFIED;

            if(tr->active_cp->queue_empty())
            {
                tr->active_cp->insert_queue(tr->tr_id);

                tr->active_cp->change_state(tr->vaddress,tr->llc_state, tr);



                tr->timestamp += llc_lookup_time;
                llc_busy_time += llc_lookup_time;
                tr->prev_state = tr->state;
                tr->state = EXIT;
            }
            else
            {
                tr->active_cp->insert_queue(tr->tr_id);
                tr->timestamp = BLOCKED;
                tr->prev_state = tr->state;
                tr->state = MLC_RSM_LLC_LOOKUP;
            }
            break;
        }
        case MLC_RSM_LLC_LOOKUP :
        {
            if(tr->active_cp->queue_head() == tr->tr_id)
            {

                tr->active_cp->change_state(tr->vaddress,tr->llc_state,tr);

                tr->timestamp = global_clock + llc_lookup_time;
                llc_busy_time += llc_lookup_time;
                tr->prev_state = tr->state;
                tr->state = EXIT;
            }
            break;
        }

            /* STATE MACHINE for MLC REPLACEMENT ends here */

        default :
            if(DEBUG) printf("ERROR: Non existant state \n");
        } /* END of SWITCH CASE FOR READ */

        break;
    }

    case WRITE :
    {
        /* STATE MACHINE FOR WRITE */
        switch(tr->state)
        {
        case START :
        {
            tr->prev_state = tr->state;
            tr->state = MLC_BUS_TRANSFER;
            tr->cache = tr->cpuid;
            tr->active_cp = &(clevel[MLC].cache[tr->cache]);
            tr->timestamp += core_transfer_time;
            break;
        }

        case EXIT :
        {
            if(tr->prev_state == MLC_RSM_LLC_TRANSFER || tr->prev_state == MLC_RSM_LLC_LOOKUP
                    || tr->prev_state == MLC_RESPONSE_TRANSFER ||tr->prev_state == MLC_BLOCKED_HEAD_QUEUE )
            {
                if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                    if(DEBUG) printf("ERROR in deleteing from queue while exiting\n");
                tr->active_cp->delete_blocked_queue(tr->tr_id);
                int bindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid;
                clevel[LLC].cache[bindex].delete_blocked_queue(tr->tr_id);
            }
            if(tr->prev_state == SNOOP_BLOCKED)
                tr->active_cp->delete_blocked_queue(tr->tr_id);




            break;
        }

        case MLC_BUS_TRANSFER :
        {
            tr->mem_queue_wait = 0;
            if(tr->active_cp->queue_empty())
            {
                tr->prev_state = tr->state;
                tr->state = MLC_LOOK_UP;
                //Measure Response time removing the trace blocking
                tr->enter_time = global_clock - core_transfer_time;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;
            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = MLC_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->mlcq_enter = tr->timestamp;
                tr->timestamp = BLOCKED;
            }
            break;
        }
        case MLC_QUEUED :
        {
            if( tr->tr_id == tr->active_cp->queue_head())
            {
                tr->mlc_queue_wait += global_clock - tr->mlcq_enter;
                if(DEBUG)
                    printf("TRANSACTION : MLC QUEUE WAIT :%ld\n for TR:%ld", tr->mlc_queue_wait, tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = MLC_LOOK_UP;
                //Measure Response time removing the trace blocking
                tr->enter_time = global_clock - core_transfer_time;
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                tr->timestamp = global_clock + mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;
            }
            break;
        }
        case MLC_LOOK_UP :
        {
            if(!tr->bq_delete)
            {
                if(!tr->mlc_bq_overflow)
                {
                    tr->active_cp->refs++;
                    tr->active_cp->refs_per_core[tr->cpuid]++;
                    //tr->active_cp->refs_per_pri[tr->pri]++;
                    tr->active_cp->writes++;
                }
                else
                    tr->mlc_bq_overflow = false;

            }

            if(tr->cstate == MODIFIED || tr->cstate == EXCLUSIVE)
            {
                if(tr->bq_delete)
                    tr->bq_delete = false;

                // if(l1prefetch_enable == 1)
                //tr->active_cp->prefetched_hit_check(tr->address,tr);


                tr->prev_state = tr->state;
                tr->state = EXIT;
                tr->active_cp->delete_blocked_queue(tr->tr_id);
                if (tr->active_cp->delete_queue_tr(tr->tr_id)!= tr->tr_id)
                    if(DEBUG) printf("ERROR: Deleting from MLC queue\n");


                if(tr->cstate == EXCLUSIVE)
                    tr->active_cp->change_state(tr->address, MODIFIED, tr);

                tr->mlc_queue_wait = 0;

                tr->timestamp += core_transfer_time;
                transaction_commit(tr);

            }
            else
            {
                if(tr->active_cp->blocked_queue_full() & !tr->bq_delete)
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_BQ_OVERFLOW;
                    tr->mlcq_enter = tr->timestamp;
                    tr->timestamp = BLOCKED;
                    tr->mlc_bq_overflow = true;
                    break;
                }

                if(tr->bq_delete)
                    tr->bq_delete = false;
                /* Assuming 32 bit address, first  bit determine which LLC address
                ** is mapped to */
                int cacheindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid;

                if (tr->active_cp->delete_queue_tr(tr->tr_id)!= tr->tr_id)
                    if(DEBUG) printf("ERROR: Deleting from MLC queue\n");

                if(!tr->active_cp->insert_blocked_queue(tr->tr_id))
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_MSHR_PENDING;
                    tr->mlcq_enter = tr->timestamp;
                    tr->timestamp = BLOCKED;
                }
                else
                {
                    tr->active_cp->misses++;
                    tr->active_cp->misses_per_core[tr->cpuid]++;
                    processor[tr->tid].l1misses++;
                    processor[tr->tid].bank_touch[cacheindex]++;
                    processor[tr->tid].per_flow_packets[cacheindex]++;
                    //tr->slack = processor[tr->tid].returnSlackPriority(tr->rob_entry,false);
                    processor[tr->tid].rob_array[tr->rob_entry].l1miss = 1;
                    processor[tr->tid].current_outstanding_packets++;

                    //tr->active_cp->misses_per_pri[tr->pri]++;
                    tr->active_cp = &(clevel[LLC].cache[cacheindex]);
                    tr->prev_state = tr->state;
                    tr->llc_transfer_state = LLC_BUS_TRANSFER;
                    tr->state = LLC_ICN_OVERFLOW;
                    //tr->src = tr->cache;
                    tr->src = cpu_network_layout[tr->cpuid];
                    tr->dst = cache_network_layout[cacheindex];
                    tr->msg_size = CADDR_SIZE;
                    addr_msgs++;
                    tr->timestamp += llc_transfer_time ;
                    if(RECORD_NOC && tr->cache != cacheindex)
                        gzprintf(rec_noc_fp,"DRQ   %d %d 4 %lld\n",tr->cache, cacheindex, global_clock);
                    tr->cache = CORES + cacheindex;

                }
            }
            break;
        }

        case MLC_BQ_OVERFLOW :
        {
            if(!tr->active_cp->blocked_queue_full())
            {
                if(DEBUG)
                    printf("TRANSACTION : MLC BQ QUEUE OVERFLOW for TR :%lld\n", tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = MLC_QUEUED;
                //          tr->mlc_bq_overflow = false;
            }
            break;
        }


        case MLC_MSHR_PENDING :
        {
            if(tr->mshr_pending[MLC])
            {
                if(DEBUG)
                    printf("TRANSACTION : MLC QUEUE WAIT :%ld for TR :%lld\n", tr->mlc_queue_wait, tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = MLC_QUEUED;
                tr->active_cp->insert_queue_after_head(tr->tr_id);
                tr->mshr_pending[MLC] = false;
                tr->bq_delete = true;
            }
            break;
        }

        case LLC_ICN_OVERFLOW :
        {
            if(SHORT_CIRCUIT)
            {
                tr->state = tr->llc_transfer_state;
                tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                tr->prev_state = LLC_ICN_OVERFLOW;
                //csim_inj_msgs++;
            }
            else
            {
                if(icn_func_sim[tr->tid])
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    per_core_icn_lat[tr->tid] += SHORT_CIRCUIT_ICN_LAT;
                    per_core_icn_msgs[tr->tid] ++;
                    break;
                }

                if(tr->src == tr->dst)
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock + 1;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                }
                else if(nic_queue_full(tr->src))
                    tr->timestamp = BLOCKED;
                else
                {
                    tr->icn_trans_comp = false;
                    tr->msg_inj_time = global_clock;

                    tr->timestamp = BLOCKED;
                    insert_nic_queue(tr->src, tr->dst, tr->msg_size, global_clock, tr->tr_id);
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    tr->state = LLC_ICN_TRANSFER;
                }
            }
            break;
        }

        case LLC_ICN_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                total_icn_msgs++;
                total_icn_latency += global_clock - tr->msg_inj_time;
                per_core_icn_lat[tr->tid] += global_clock - tr->msg_inj_time;
                per_core_icn_msgs[tr->tid] ++;

                tr->icn_trans_comp = false;
                tr->timestamp = global_clock + 1;
                tr->prev_state = LLC_ICN_TRANSFER;
                tr->state = tr->llc_transfer_state;
            }
            break;
        }

        case MEM_ICN_OVERFLOW :
        {
            if(MEM_SHORT_CIRCUIT)
            {
                tr->state = tr->mem_transfer_state;
                tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                tr->prev_state = LLC_ICN_OVERFLOW;
                //csim_inj_msgs++;
            }
            else
            {
                if(icn_func_sim[tr->tid])
                {
                    tr->state = tr->mem_transfer_state;
                    tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                    tr->prev_state = MEM_ICN_OVERFLOW;
                    per_core_icn_lat[tr->tid] += SHORT_CIRCUIT_ICN_LAT;
                    per_core_icn_msgs[tr->tid] ++;
                    break;
                }

                if(tr->src == tr->dst)
                {
                    tr->state = tr->mem_transfer_state;
                    tr->timestamp = global_clock + 1;
                    tr->prev_state = MEM_ICN_OVERFLOW;
                }
                else if(nic_queue_full(tr->src))
                    tr->timestamp = BLOCKED;
                else
                {
                    tr->icn_trans_comp = false;
                    tr->msg_inj_time = global_clock;
                    tr->timestamp = BLOCKED;
                    insert_nic_queue(tr->src, tr->dst, tr->msg_size, global_clock, tr->tr_id);
                    tr->prev_state = MEM_ICN_OVERFLOW;
                    tr->state = MEM_ICN_TRANSFER;
                }
            }
            break;
        }



        case MEM_ICN_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                total_icn_msgs++;
                total_icn_latency += global_clock - tr->msg_inj_time;
                per_core_icn_lat[tr->tid] += global_clock - tr->msg_inj_time;
                per_core_icn_msgs[tr->tid] ++;

                tr->icn_trans_comp = false;
                tr->timestamp = global_clock + 1;
                tr->prev_state = MEM_ICN_TRANSFER;
                tr->state = tr->mem_transfer_state;
            }
            break;
        }



        case LLC_BUS_TRANSFER :
        {
            if(tr->active_cp->queue_full())
            {
                tr->timestamp = BLOCKED;
            }

            else if(tr->active_cp->queue_empty())
            {
                tr->prev_state = tr->state;
                tr->state = LLC_LOOK_UP;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                if(tr->fat_write)
                {
                    TRANSTYPE *tr_new;
                    long long temp_id = tr->tr_id;
                    tr_pool.insert(tr_pool.begin(), TRANSTYPE());
                    tr_new = &(tr_pool.at(0));
                    if(temp_id != tr->tr_id)
                        tr = map_transaction(temp_id);

                    tr_new->copy(*tr);
                    tr_new->fat_write = true;
                    tr->fat_write = false;
                    tr_new->linesize = tr->linesize;
                    tr_new->tr_id = transaction_count++;
                    tr_new->state = LLC_REPLACE_SM;
                    tr_new->timestamp = global_clock;
                }
                tr->timestamp = global_clock + llc_lookup_time;
                llc_busy_time += llc_lookup_time;

            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = LLC_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->llcq_enter = global_clock;
                tr->timestamp = BLOCKED;
            }
            break;
        }
        case LLC_QUEUED :
        {
            if( tr->tr_id == tr->active_cp->queue_head())
            {
                tr->llc_queue_wait += global_clock - tr->llcq_enter;
                tr->prev_state = tr->state;
                tr->state = LLC_LOOK_UP;
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                if(tr->fat_write)
                {
                    TRANSTYPE *tr_new;
                    long long temp_id = tr->tr_id;
                    tr_pool.insert(tr_pool.begin(), TRANSTYPE());
                    tr_new = &(tr_pool.at(0));

                    if(temp_id != tr->tr_id)
                        tr = map_transaction(temp_id);
                    tr_new->copy(*tr);
                    tr_new->fat_write = true;
                    tr->fat_write = false;
                    tr_new->linesize = tr->linesize;
                    tr_new->tr_id = transaction_count++;
                    tr_new->state = LLC_REPLACE_SM;
                    tr_new->timestamp = global_clock;
                }

                tr->timestamp = global_clock + llc_lookup_time;
                llc_busy_time += llc_lookup_time;
            }
            break;
        }
        case LLC_LOOK_UP :
        {
            if(!tr->bq_delete)
            {
                if(!tr->llc_bq_overflow)
                {
                    // printf("LLC Count %d\t",tr->tr_id);
                    if(tr->cstate == INVALID /*|| tr->cstate == SHARED*/)
                    {
                        tr->active_cp->refs++;
                        tr->active_cp->refs_per_core[tr->cpuid]++;
                        //tr->active_cp->refs_per_pri[tr->pri]++;
                    }
                    else
                    {
                        tr->active_cp->refs++;
                        tr->active_cp->refs_per_core[tr->cpuid]++;
                        ///tr->active_cp->refs_per_pri[tr->pri]++;
                    }
                    tr->active_cp->writes++;
                }
                else
                    tr->llc_bq_overflow = false;

                if(tr->cstate != MODIFIED && tr->cstate != EXCLUSIVE
                        && tr->active_cp->blocked_queue_full())
                {
                    tr->prev_state = tr->state;
                    tr->llcq_enter = global_clock;
                    tr->state = LLC_BQ_OVERFLOW;
                    tr->timestamp = BLOCKED;
                    tr->llc_bq_overflow = true;
                    break;
                }

            }
            else
            {
                tr->bq_delete = false;
            }


            //Nachi
            //Check if data was a prefetched data.
            //if(tr->cstate != INVALID)
            //tr->active_cp->prefetched_hit_check(tr->address,tr);

            if(tr->call_issue_prefetches == false)
            {
                int curr_trid = tr->tr_id;
                if(tr->cstate != INVALID)
                {
                    tr->l2hit = 1;
                    tr->l2miss = 0;
                }
                else
                {
                    tr->l2hit = 0;
                    tr->l2miss = 1;
                }
                IssuePrefetches(global_clock, tr->tr_id);

                //If the tr_pool was rearranged by the OS to a different location, then re-map.
                if(tr->tr_id != curr_trid)
                    tr = map_transaction(curr_trid);

                tr->call_issue_prefetches = true;
            }


            if(tr->cstate == EXCLUSIVE || tr->cstate == SHARED)
            {
                TRANSTYPE *tr_snoop[CORES];

                if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                    if(DEBUG) printf("ERROR: In deleting from Queue while blocking for snoop\n" );

                if(!tr->active_cp->insert_blocked_queue(tr->tr_id))
                {
                    tr->prev_state = tr->state;
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                    tr->state = LLC_MSHR_PENDING;
                }
                else
                {

                    tr->snoop_invalidate = TRUE;
                    tr->prev_state = tr->state;
                    tr->state = SNOOP_BLOCKED;
                    tr->snoopq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                    long long trid = tr->tr_id;
                    for (int i =0,j =0; i < CORES  ; i++)
                    {
                        tr->snoop_done[i] = FALSE;
                        if(i == tr->cpuid)
                            continue;
#if DIRECTORY
                        if(clevel[MLC].cache[i].look_up(tr->address,false,tr) == INVALID)
                            continue;
#endif                
                        tr_pool.push_back(TRANSTYPE());
                        /* STL migh relocate vectors after psushing and element
                    ** thus this might cause dangling pointers */
                        if(trid != tr->tr_id)
                            tr = map_transaction(trid);

                        tr_snoop[j] = &(tr_pool.back());
                        tr_snoop[j]->state = START;
                        tr_snoop[j]->tr_id = transaction_count++;
                        tr_snoop[j]->address = tr->address;
                        tr_snoop[j]->type = SNOOP;
                        tr_snoop[j]->parent = tr->tr_id;
                        tr_snoop[j]->cache = i;
                        tr_snoop[j]->timestamp = global_clock;
                        tr_snoop[j]->enter_time = global_clock;
                        tr_snoop[j]->cpuid = i;
                        tr_snoop[j]->tid = tr->tid;
                        tr_snoop[j]->active_cp = &(clevel[MLC].cache[i]);
                        j++;
                        tr->snoop_count = j;
                    }
                    if(DEBUG)
                        printf("sending out snoops for %d with snoop_count : %d\n",tr->tr_id,tr->snoop_count);
                }
            }

            else if(tr->cstate == MODIFIED)
            {
                int cacheindex = tr->cpuid;


                tr->active_cp->writebacks++;

                tr->active_cp->change_state(tr->address, EXCLUSIVE,tr);
                tr->active_cp->delete_blocked_queue(tr->tr_id);
                tr->active_cp->delete_queue_tr(tr->tr_id);

                tr->mlc_state = MODIFIED;

                tr->active_cp = &(clevel[MLC].cache[cacheindex]);
                tr->prev_state = tr->state;
                tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
                tr->state = LLC_ICN_OVERFLOW;
                tr->src = cache_network_layout[tr->cache - CORES];
                tr->msg_size = CLINE_SIZE;
                data_msgs++;
                //printf("imsg size : %d, %d\n",tr->msg_size, tr->linesize);
                //tr->dst = cacheindex;
                tr->dst = cpu_network_layout[tr->cpuid];
                tr->timestamp += llc_transfer_time;

                if(RECORD_NOC && tr->src != tr->dst)
                    gzprintf(rec_noc_fp,"DRSP  %d %d 64 %lld\n",tr->src, tr->dst, global_clock);
                tr->cache = cacheindex;
                // Is this necessary ??
                TRANSTYPE *tr_mem;
                long long trid = tr->tr_id;
                tr_pool.push_back(TRANSTYPE());
                /* STL migh relocate vectors after psushing and element
                ** thus this might cause dangling pointers */
                if(trid != tr->tr_id)
                    tr = map_transaction(trid);

                tr_mem = &(tr_pool.back());
                tr_mem->tr_id = transaction_count++;
                tr_mem->address = tr->address;
                tr_mem->type = WRITEBACK;
                tr_mem->cache = MEM;
                tr_mem->cstate = MODIFIED;
                tr_mem->memq_enter = global_clock;

                if(DRAMSIM_MEMORY)
                {
                    //tr_mem->timestamp = global_clock + mem_transfer_time;
                    //Inserting into the memory considering the mem controller id.
                    //mem->addDRAMTransaction(isWrite, addr);
                    uint64_t physical_address;
                    physical_address = tr_mem->address;
                    //printf("\n TRID:%d :: Insert WRITE at %lld ; ADDR : %0x%1x",tr_mem->tr_id, global_clock,physical_address);

                    int mem_ctr_id = DECODE_MEM_CTRLR(tr_mem->address, tr_mem->cpuid);

                    if(mem_ctr_id == 0)
                        mem1->addDRAMTransaction(true, physical_address);
                    else if(mem_ctr_id == 1)
                        mem2->addDRAMTransaction(true, physical_address);
                    else if(mem_ctr_id == 2)
                        mem3->addDRAMTransaction(true, physical_address);
                    else if(mem_ctr_id == 3)
                        mem4->addDRAMTransaction(true, physical_address);
                    tr_mem->timestamp = global_clock+9999;
                }
                else
                {
                    tr_mem->timestamp = global_clock + mem_transfer_time;
                }
                tr_mem->enter_time = tr->enter_time;
                tr_mem->cpuid = tr->cpuid;
                tr_mem->tid = tr->tid;
                tr_mem->active_cp = MEMORY;
                tr_mem->prev_state = LLC_LOOK_UP;
                tr_mem->state = MEM_BUS_TRANSFER;
            }

            else if(tr->cstate == INVALID)
            {
                if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                    if(DEBUG)  printf("ERROR: In deleting from Queue while blocking for memory\n" );
                if(!tr->active_cp->insert_blocked_queue(tr->tr_id))
                {
                    tr->prev_state = tr->state;
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                    tr->state = LLC_MSHR_PENDING;
                }
                else
                {

                    tr->llc_memq_miss = true;
                    tr->active_cp->misses++;
                    tr->active_cp->misses_per_core[tr->cpuid]++;
                    processor[tr->tid].l2misses++;
                    processor[tr->tid].rob_array[tr->rob_entry].l2miss = 1;


                    /* Nachi -Up5*/
                    /* The function that decides if prefetch is to be issued. It determines the next address to be prefetched. */
                    //long long trid = tr->tr_id;
                    //IssuePrefetches(global_clock,  tr->tr_id);
                    //Re-map tr
                    //tr = map_transaction(trid);

                    tr->active_cp = MEMORY;
                    tr->prev_state = tr->state ;

                    int mem_ctr_id = DECODE_MEM_CTRLR(tr->address, tr->cpuid);
                    int cacheindex = DECODE_BANK(tr->address, tr->cpuid);
                    tr->state = MEM_ICN_OVERFLOW;
                    tr->mem_transfer_state = MEM_BUS_TRANSFER;
                    tr->src = cache_network_layout[cacheindex];
                    tr->dst = mem_network_layout[mem_ctr_id];
                    tr->msg_size = CADDR_SIZE;
                    addr_msgs++;
                    tr->memq_enter = global_clock;
                    if(DRAMSIM_MEMORY)
                    {
                        //tr->timestamp = global_clock + mem_transfer_time;
                        //Inserting into the memory considering the mem controller id.
                        uint64_t physical_address;
                        physical_address = tr->address;
                        //printf("\n TRID:%d :: Insert READ at %lld ; ADDR : %0x%1x",tr->tr_id, global_clock,physical_address);

                        if(mem_ctr_id == 0)
                            mem1->addDRAMTransaction(false, physical_address);
                        else if(mem_ctr_id == 1)
                            mem2->addDRAMTransaction(false, physical_address);
                        else if(mem_ctr_id == 2)
                            mem3->addDRAMTransaction(false, physical_address);
                        else if(mem_ctr_id == 3)
                            mem4->addDRAMTransaction(false, physical_address);
                        tr->timestamp = global_clock+9999;
                    }
                    else
                    {
                        tr->timestamp = global_clock + mem_transfer_time;
                    }

                    tr->cache = MEM;
                    tr->llc_state = EXCLUSIVE;
                    tr->mlc_state = MODIFIED;
                }
            }
            break;
        }

        case LLC_MSHR_PENDING :
        {
            if(tr->mshr_pending[LLC])
            {
                tr->prev_state = tr->state;
                tr->state = LLC_QUEUED;
                tr->active_cp->insert_queue_after_head(tr->tr_id);
                tr->mshr_pending[LLC] = false;
                tr->bq_delete = true;
                tr->from_blocked_queue = true;
            }

            break;
        }

        case LLC_BQ_OVERFLOW :
        {
            if(!tr->active_cp->blocked_queue_full())
            {
                if(DEBUG)
                    printf("TRANSACTION : LLC BQ QUEUE OVERFLOW for TR :%lld\n", tr->tr_id);
                tr->prev_state = tr->state;
                tr->state = LLC_QUEUED;
                //tr->llc_bq_overflow = false;
            }
            else
            {
                if(tr->active_cp->queue.size() > 1)
                {
                    TRANSTYPE *tmp = map_transaction(tr->active_cp->queue[1]);
                    if(tmp->from_blocked_queue == true)
                    {
                        tr->active_cp->delete_queue_tr(tr->tr_id);
                        std::vector<long long>::iterator start = tr->active_cp->queue.begin();
                        start++;
                        tr->active_cp->queue.insert(start, tr->tr_id);
                    }
                }
            }
            break;
        }

        case MEM_BUS_TRANSFER :
        {
            if(tr->active_cp->queue_full())
            {
                tr->timestamp = BLOCKED;
            }
            else if(tr->active_cp->queue_empty())
            {
                tr->llc_first = TRUE;
                tr->active_cp =
                        &(clevel[LLC].cache[llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid]);
                tr->cache = CORES + (llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid);
                tr->prev_state = MEM_QUEUED;

                int mem_ctr_id = DECODE_MEM_CTRLR(tr->address, tr->cpuid);
                int cacheindex = DECODE_BANK(tr->address, tr->cpuid);
                tr->state = MEM_ICN_OVERFLOW;
                tr->mem_transfer_state = LLC_BLOCKED_QUEUE_HEAD;
                tr->dst = cache_network_layout[cacheindex];
                tr->src = mem_network_layout[mem_ctr_id];
                tr->msg_size = CLINE_SIZE;
                data_msgs++;
                tr->timestamp = global_clock + memory_access_time;

            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = MEM_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->timestamp = BLOCKED;
            }
            break;
        }

        case MEM_QUEUED :
        {
            if(tr->tr_id == tr->active_cp->queue_head())
            {
                tr->active_cp->delete_queue_tr(tr->tr_id);
                tr->timestamp = global_clock + memory_access_time;
                tr->llc_first = TRUE;
                tr->state = LLC_BLOCKED_QUEUE_HEAD;
                tr->active_cp =
                        &(clevel[LLC].cache[llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid]);
                tr->cache = CORES + (llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid) ;
                tr->prev_state = MEM_QUEUED;
            }
            break;

        }

        case SNOOP_BLOCKED :
        {
            int done = FALSE, count=0;
            int snoop_state = INVALID ;
            for(int i = 0; i< CORES ; i++)
                if( tr->snoop_done[i] == TRUE)
                    count++;
            if(DEBUG) printf("in SNOOP BLOCKED count %d snoop_count %d\n",count,tr->snoop_count);
            if(count == tr->snoop_count /*&& tr->prev_state == LLC_REPLACE_SM*/)
            {
                done = TRUE;
                /* for(int i = 0; i< CORES ; i++)
                   tr->snoop_done[i] = FALSE; */
                if(DEBUG) printf("in SNOOP BLOCKED count %d\n",count);
            }
            /*
                 else if(count == CORES - 1 && tr->prev_state == LLC_LOOK_UP)
                 {
                 done = TRUE;
                 for(int i = 0; i< CORES ; i++)
                 tr->snoop_done[i] = FALSE;
                 if(DEBUG) printf("in SNOOP BLOCKED count %d\n",count);
                 }
                 else if(count == CORES && tr->prev_state != LLC_LOOK_UP)
                 {
                 done = TRUE;
                 for(int i = 0; i< CORES ; i++)
                 tr->snoop_done[i] = FALSE;
                 if(DEBUG) printf("in SNOOP BLOCKED count %d\n",count);
                 }*/

            if(done)
            {
                tr->snoop_wait += global_clock - tr->snoopq_enter;
                for(int i =0; i<CORES ; i++)
                {
                    if(!tr->snoop_done[i])
                        continue;
                    tr->snoop_done[i] = FALSE;
                    if(tr->snoop_state[i] == MODIFIED)
                    {
                        tr->active_cp->writebacks++;
                        if(tr->prev_state == LLC_LOOK_UP)
                        {
                            if(tr->cpuid != i)
                            {
                                TRANSTYPE *tr_mem;
                                snoop_state = MODIFIED;
                                if(DEBUG) printf("SNOOP FOR TR %d resulted in MODIFIED ", tr->tr_id);
                                long long trid = tr->tr_id;

                                tr_pool.push_back(TRANSTYPE());
                                /* STL migh relocate vectors after psushing and element
                        ** thus this might cause dangling pointers */
                                if(trid != tr->tr_id)
                                    tr = map_transaction(trid);

                                tr_mem = &(tr_pool.back());
                                tr_mem->tr_id = transaction_count++;
                                tr_mem->address = tr->address;
                                tr_mem->type = WRITEBACK;
                                tr_mem->cache = MEM;
                                tr_mem->memq_enter = global_clock;
                                if(DRAMSIM_MEMORY)
                                {
                                    //tr_mem->timestamp = global_clock + mem_transfer_time;

                                    //Inserting into the memory considering the mem controller id.
                                    //mem->addDRAMTransaction(isWrite, addr);
                                    uint64_t physical_address;
                                    physical_address = tr_mem->address;
                                    //printf("\n TRID:%d :: Insert WRITE at %lld ; ADDR : %0x%1x",tr_mem->tr_id, global_clock,physical_address);

                                    int mem_ctr_id = DECODE_MEM_CTRLR(tr_mem->address, tr_mem->cpuid);

                                    if(mem_ctr_id == 0)
                                        mem1->addDRAMTransaction(true, physical_address);
                                    else if(mem_ctr_id == 1)
                                        mem2->addDRAMTransaction(true, physical_address);
                                    else if(mem_ctr_id == 2)
                                        mem3->addDRAMTransaction(true, physical_address);
                                    else if(mem_ctr_id == 3)
                                        mem4->addDRAMTransaction(true, physical_address);
                                    tr_mem->timestamp = global_clock+9999;
                                }
                                else
                                {
                                    tr_mem->timestamp = global_clock + mem_transfer_time;
                                }
                                tr_mem->enter_time = global_clock;
                                tr_mem->cpuid = tr->cpuid;
                                tr_mem->tid = tr->tid;
                                tr_mem->active_cp = MEMORY;
                                tr_mem->prev_state = tr->state;
                                tr_mem->state = MEM_BUS_TRANSFER;
                            }
                        }
                        else
                        {

                            //  tr->active_cp->update_data(tr->address, tr);

                            tr->active_cp = MEMORY;
                            tr->memq_enter = global_clock;
                            if(DRAMSIM_MEMORY)
                            {
                                //tr->timestamp = global_clock + mem_transfer_time;
                                //Inserting into the memory considering the mem controller id.
                                uint64_t physical_address;
                                physical_address = tr->address;
                                //printf("\n TRID:%d :: Insert READ at %lld ; ADDR : %0x%1x",tr->tr_id, global_clock,physical_address);
                                int mem_ctr_id = DECODE_MEM_CTRLR(tr->address, tr->cpuid);
                                if(mem_ctr_id == 0)
                                    mem1->addDRAMTransaction(true, physical_address);
                                else if(mem_ctr_id == 1)
                                    mem2->addDRAMTransaction(true, physical_address);
                                else if(mem_ctr_id == 2)
                                    mem3->addDRAMTransaction(true, physical_address);
                                else if(mem_ctr_id == 3)
                                    mem4->addDRAMTransaction(true, physical_address);
                                tr->timestamp = global_clock+9999;
                            }
                            else
                            {
                                tr->timestamp = global_clock + mem_transfer_time;
                            }

                            tr->prev_state = tr->state;
                            tr->state = MEM_BUS_TRANSFER;
                            tr->type = WRITEBACK;
                        }
                        snoop_state = MODIFIED;
                        if(DEBUG) printf("SNOOP FOR TR %d resulted in MODIFIED", tr->tr_id);
                        break;
                    }
                    if(/* i!= tr->cpuid &&*/ tr->snoop_state[i] == SHARED)
                    {
                        snoop_state = SHARED;
                        if(DEBUG) printf("SNOOP FOR TR %d resulted in SHARED", tr->tr_id);
                        break;
                    }
                    if( /*i!= tr->cpuid && */ tr->snoop_state[i] == EXCLUSIVE)
                    {
                        snoop_state = EXCLUSIVE;
                        if(DEBUG) printf("SNOOP FOR TR %d resulted in EXCLUSIVE", tr->tr_id);
                        break;
                    }

                }/* END of FOR */

                if(tr->prev_state == LLC_LOOK_UP)
                {
                    int cacheindex = tr->cpuid;

                    tr->active_cp->change_state(tr->address, EXCLUSIVE, tr);
                    tr->active_cp->delete_blocked_queue(tr->tr_id);

                    tr->mlc_state = MODIFIED;

                    tr->active_cp = &(clevel[MLC].cache[cacheindex]);
                    tr->prev_state = tr->state;
                    tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
                    tr->state = LLC_ICN_OVERFLOW;
                    tr->src = cache_network_layout[tr->cache - CORES];
                    tr->msg_size = CLINE_SIZE;
                    data_msgs++;
                    // printf("imsg size : %d, %d\n",tr->msg_size, tr->linesize);
                    // tr->dst = cacheindex;
                    tr->dst = cpu_network_layout[tr->cpuid];
                    /* APPROXIMATION for block update time */
                    tr->timestamp = global_clock + llc_lookup_time + llc_transfer_time;
                    if(RECORD_NOC && tr->src != tr->dst)
                        gzprintf(rec_noc_fp,"DRSP  %d %d 64 %lld\n",tr->src,tr->dst, global_clock);
                    llc_busy_time += llc_lookup_time;
                    tr->cache = cacheindex;
                }
                else
                {
                    if(snoop_state != MODIFIED)
                    {
                        tr->prev_state = tr->state;
                        tr->state = EXIT;
                        tr->timestamp = global_clock + llc_lookup_time;
                        llc_busy_time += llc_lookup_time;
                    }
                }

            }/* End of Done */

            break;
        }

        case LLC_BLOCKED_QUEUE_HEAD :
        {

            if(tr->llc_first)
            {
                //MEMORY->delete_queue_tr(tr->tr_id);
                if(DEBUG)
                {
                    if(tr->llc_memq_miss != true)
                    {
                        printf("ERR\n");
                        tr->hist();
                    }
                    else
                        temp_miss_count++;

                    int llc_misses=0;
                    for(int i=0; i<num_llc_banks; i++)
                        llc_misses += clevel[LLC].cache[i].misses;
                    if(tr->history[tr->history.size() - 3].state != LLC_LOOK_UP)
                    {
                        printf("ERR\n");
                        tr->hist();
                    }
                    printf("mem latency %d : llc misses %d temp_miss_count %d\n", global_clock - tr->memq_enter, llc_misses, temp_miss_count);
                }

                tr->active_cp->insert_queue_after_head(tr->tr_id);
                tr->llc_first = FALSE;
                if(tr->tr_id == tr->active_cp->queue_head())
                {
                    tr->prev_state = tr->state;
                    tr->state = LLC_REPLACE_SM;
                }
                else
                {
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                }

            }
            else
            {

                int head = tr->active_cp->queue_head();

                TRANSTYPE *head_tr = map_transaction(head);
                if(head_tr->state == LLC_BQ_OVERFLOW )
                {
                    tr->active_cp->queue.erase(tr->active_cp->queue.begin());
                    tr->active_cp->rq_size--;
                    tr->active_cp->insert_queue_after_head(head);
                }

                if(tr->tr_id == tr->active_cp->queue_head())
                {
                    tr->llc_queue_wait += global_clock - tr->llcq_enter;
                    tr->prev_state = tr->state;
                    tr->state = LLC_REPLACE_SM;
                }
            }

            break;
        }


        case LLC_REPLACE_SM :
        {
            int pri;
            /* Assumption victim lookup time inclusive of update time for the
              ** victim with new block from memory and done at same time */
            tr->timestamp = global_clock + llc_victim_lookup_time + llc_lookup_time;
            llc_busy_time += llc_victim_lookup_time;
            llc_busy_time += llc_lookup_time;
            std::vector<long long> vaddr;
            tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, &vaddr, tr->llc_state, tr);

            if(vaddr.size()== 0)
            {
                tr->prev_state = tr->state;
                tr->state = LLC_RSM_LOOKUP_COMPLETE;
            }

            int vindex = 0;
            while(vindex < vaddr.size())
            {

                tr->vaddress = vaddr[vindex];
                vindex++;

                if(tr->vaddress != tr->address)
                    tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);
                else
                    tr->vstate = INVALID;

                tr->prev_state = tr->state;
                if(INVALID == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    tr->state = LLC_RSM_LOOKUP_COMPLETE;
                    //   tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos, tr->pri);
                }

                else if(MODIFIED == tr->vstate)
                {
                    //  tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos, tr->pri);
                    TRANSTYPE *tr_mem;
                    tr->active_cp->writebacks++;

                    long long trid = tr->tr_id;
                    tr_pool.push_back(TRANSTYPE());
                    /* STL migh relocate vectors after psushing and element
                  ** thus this might cause dangling pointers */

                    tr = map_transaction(trid);

                    tr_mem = &(tr_pool.back());
                    tr_mem->tr_id = transaction_count++;
                    tr_mem->address = tr->address;
                    tr_mem->type = WRITEBACK;
                    tr_mem->cache = MEM;
                    tr_mem->memq_enter = global_clock;
                    if(DRAMSIM_MEMORY)
                    {
                        //tr_mem->timestamp = global_clock + mem_transfer_time;

                        //Inserting into the memory considering the mem controller id.
                        //mem->addDRAMTransaction(isWrite, addr);
                        uint64_t physical_address;
                        physical_address = tr_mem->address;
                        //printf("\n TRID:%d :: Insert WRITE at %lld ; ADDR : %0x%1x",tr_mem->tr_id, global_clock,physical_address);

                        int mem_ctr_id = DECODE_MEM_CTRLR(tr_mem->address, tr_mem->cpuid);

                        if(mem_ctr_id == 0)
                            mem1->addDRAMTransaction(true, physical_address);
                        else if(mem_ctr_id == 1)
                            mem2->addDRAMTransaction(true, physical_address);
                        else if(mem_ctr_id == 2)
                            mem3->addDRAMTransaction(true, physical_address);
                        else if(mem_ctr_id == 3)
                            mem4->addDRAMTransaction(true, physical_address);
                        tr_mem->timestamp = global_clock+9999;
                    }
                    else
                    {
                        tr_mem->timestamp = global_clock + mem_transfer_time;
                    }


                    tr_mem->enter_time = global_clock;
                    tr_mem->cpuid = tr->cpuid;
                    tr_mem->tid = tr->tid;
                    tr_mem->active_cp = MEMORY;
                    tr_mem->prev_state = tr->state;
                    tr_mem->state = MEM_BUS_TRANSFER;

                    tr->prev_state = tr->state;
                    tr->state = LLC_RSM_LOOKUP_COMPLETE;


                }
                else if(EXCLUSIVE == tr->vstate || SHARED == tr->vstate )
                {
                    TRANSTYPE *tr_new;
                    TRANSTYPE *tr_snoop[CORES];

                    long long trid = tr->tr_id;
                    tr_pool.push_back(TRANSTYPE());
                    /* STL migh relocate vectors after psushing and element
                  ** thus this might cause dangling pointers */

                    tr = map_transaction(trid);

                    tr_new = &(tr_pool.back());
                    tr_new->copy(*tr);
                    tr_new->tr_id = transaction_count++;
                    tr_new->address = tr->vaddress;

                    tr_new->snoop_invalidate = TRUE;


                    //if(!tr_new->active_cp->insert_blocked_queue(tr_new->tr_id))
                    //{
                    // if(DEBUG)
                    // printf("Should not be here!!!! Inside MSHR LLC RSM case:%lld, new:%lld\n",tr->tr_id,tr_new->tr_id);
                    //DEBUG=1;
                    // tr->prev_state = tr->state;
                    //tr->active_cp->look_up(tr->vaddress,TRUE);
                    //tr->state = LLC_REPLACE_SM;
                    //tr->timestamp = global_clock;
                    //tr_pool.pop_back();
                    //tr_new->active_cp->delete_blocked_queue(tr_new->tr_id);
                    // getchar();
                    //break;
                    //}
                    //else
                    {
                        //   tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos, tr->pri);
                        tr_new->prev_state = tr->state;
                        tr_new->state = SNOOP_BLOCKED;
                        tr_new->timestamp = BLOCKED;
                        long long trid = tr->tr_id;

                        for (int i =0,j =0; i < CORES  ; i++)
                        {
                            tr_new->snoop_done[i] = FALSE;
                            //  if(i == tr_new->cpuid)
                            //  continue;

#if DIRECTORY
                            if(clevel[MLC].cache[i].look_up(tr_new->address,false,tr) == INVALID)
                                continue;
#endif
                            tr_pool.push_back(TRANSTYPE());
                            /* STL migh relocate vectors after psushing and element
                      ** thus this might cause dangling pointers */

                            tr = map_transaction(trid);

                            tr_snoop[j] = &(tr_pool.back());
                            tr_snoop[j]->tr_id = transaction_count++;
                            tr_snoop[j]->state = START;
                            tr_snoop[j]->address = tr_new->address;
                            tr_snoop[j]->type = SNOOP;
                            tr_snoop[j]->parent = tr_new->tr_id;
                            tr_snoop[j]->cache = i;
                            tr_snoop[j]->timestamp = global_clock;
                            tr_snoop[j]->enter_time = global_clock;
                            tr_snoop[j]->cpuid = i;
                            tr_snoop[j]->tid = tr_new->tid;
                            tr_snoop[j]->active_cp = &(clevel[MLC].cache[i]);
                            j++;
                            tr_new->snoop_count = j;
                        }
                        tr->prev_state = tr->state;
                        tr->state = LLC_RSM_LOOKUP_COMPLETE;

                    }
                }
            }
            if(tr->fat_write || tr->mlc_wbx_fat_write)
                tr->state = EXIT;

            break;
        }

        case LLC_RSM_LOOKUP_COMPLETE:
        {
            int cacheindex = tr->cpuid;
            //          tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->llc_state,tr->rep_pos);
            tr->active_cp->delete_blocked_queue(tr->tr_id);
            if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                if(DEBUG) printf("ERROR: In deleting from Queue while LLC REPLACEMENT\n" );

            tr->active_cp = &(clevel[MLC].cache[cacheindex]);
            tr->prev_state = tr->state;
            tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
            tr->state = LLC_ICN_OVERFLOW;
            tr->src = cache_network_layout[tr->cache - CORES];
            tr->msg_size = CLINE_SIZE;
            data_msgs++;
            //  printf("imsg size : %d, %d\n",tr->msg_size, tr->linesize);
            //tr->dst = cacheindex;
            tr->dst = cpu_network_layout[tr->cpuid];
            tr->timestamp += llc_transfer_time;
            if(RECORD_NOC && tr->src != tr->dst)
                gzprintf(rec_noc_fp,"DRSP  %d %d 64 %lld\n",tr->src,tr->dst, global_clock);
            tr->cache = cacheindex;
            break;
        }
            /* STATE MACHINE for MLC REPLACEMENT begins here */
        case MLC_RESPONSE_TRANSFER :
        {
            tr->active_cp->insert_queue_after_head(tr->tr_id);
            if(tr->active_cp->queue_head() == tr->tr_id)
            {
                tr->timestamp += core_transfer_time;
                transaction_commit(tr);
                tr->timestamp -= core_transfer_time;

                if(tr->active_cp->look_up(tr->address, false,tr) == SHARED)
                {
                    tr->active_cp->change_state(tr->address,tr->mlc_state, tr);
                    tr->prev_state = tr->state;
                    tr->state = EXIT;

                    break;
                }
                tr->vaddress = tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, NULL, INVALID, tr);
                if(tr->vaddress != tr->address)
                    tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);
                else tr->vstate = INVALID;
                tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->mlc_state,tr->rep_pos, tr);

                //if(l1prefetch_enable == 1)
                //if(tr->prefetch_transaction == 1)
                //tr->active_cp->prefetched_bit_set(tr->address,tr);

                tr->timestamp += mlc_victim_lookup_time;
                mlc_busy_time += mlc_victim_lookup_time;
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;

                if(INVALID == tr->vstate || SHARED == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_REPLACE_SM;
                }
            }
            else
            {
                tr->timestamp = BLOCKED;
                tr->prev_state = tr->state;
                tr->state = MLC_BLOCKED_HEAD_QUEUE;
            }
            break;
        }
        case MLC_BLOCKED_HEAD_QUEUE:
        {
            int head = tr->active_cp->queue_head();

            TRANSTYPE *head_tr = map_transaction(head);
            if(head_tr->state == MLC_BQ_OVERFLOW)
            {
                tr->active_cp->queue.erase(tr->active_cp->queue.begin());
                tr->active_cp->rq_size--;
                tr->active_cp->insert_queue_after_head(head);
            }

            if(tr->active_cp->queue_head() == tr->tr_id)
            {
                tr->timestamp = global_clock + core_transfer_time;
                transaction_commit(tr);
                tr->timestamp -= core_transfer_time;
                if(tr->active_cp->look_up(tr->address, false,tr) == SHARED)
                {
                    tr->active_cp->change_state(tr->address,tr->mlc_state,tr);
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                    break;
                }

                tr->vaddress = tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, NULL, INVALID, tr);
                tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->mlc_state,tr->rep_pos, tr);
                tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);

                tr->timestamp = global_clock + mlc_victim_lookup_time;
                mlc_busy_time += mlc_victim_lookup_time;
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;

                if(INVALID == tr->vstate || SHARED == tr->vstate || EXCLUSIVE == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_REPLACE_SM;
                }



            }

            break;
        }
        case MLC_REPLACE_SM :
        {
            int cacheindex = llc_shared ? DECODE_BANK(tr->vaddress,tr->cpuid): tr->cpuid;

            int bindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid;
            clevel[LLC].cache[bindex].delete_blocked_queue(tr->tr_id);
            tr->active_cp->writebacks++;
            tr->active_cp->delete_queue_tr(tr->tr_id);
            tr->active_cp->delete_blocked_queue(tr->tr_id);

            tr->active_cp = &(clevel[LLC].cache[cacheindex]);
            tr->prev_state = tr->state;
            tr->llc_transfer_state = MLC_RSM_LLC_TRANSFER;
            tr->state = LLC_ICN_OVERFLOW;
            //tr->src = tr->cache;
            tr->src = cpu_network_layout[tr->cpuid];
            tr->msg_size = (fetch_csize(tr->vdata)*SET_SEG_SIZE)/FLIT_SIZE_BYTES + CADDR_SIZE;
            wb_msgs++;
            tr->dst = cache_network_layout[cacheindex];
            tr->timestamp += llc_transfer_time;
            if(RECORD_NOC && tr->cache != cacheindex)
                gzprintf(rec_noc_fp,"WBX   %d %d 64 %lld\n", tr->cache,cacheindex, global_clock);
            tr->cache = cacheindex + CORES;
            break;
        }

        case MLC_RSM_LLC_TRANSFER :
        {
            if(EXCLUSIVE == tr->vstate)
                tr->llc_state = INVALID;
            else if(MODIFIED == tr->vstate)
                tr->llc_state = MODIFIED;

            if(tr->active_cp->queue_empty())
            {

                tr->active_cp->insert_queue(tr->tr_id);
                tr->active_cp->change_state(tr->vaddress,tr->llc_state, tr);
                
                tr->timestamp += llc_lookup_time;
                llc_busy_time += llc_lookup_time;
                tr->prev_state = tr->state;
                tr->state = EXIT;
            }
            else
            {
                tr->active_cp->insert_queue(tr->tr_id);
                tr->timestamp = BLOCKED;
                tr->prev_state = tr->state;
                tr->state = MLC_RSM_LLC_LOOKUP;
            }
            break;
        }
        case MLC_RSM_LLC_LOOKUP :
        {
            if(tr->active_cp->queue_head() == tr->tr_id)
            {

                tr->active_cp->change_state(tr->vaddress,tr->llc_state, tr);


                tr->timestamp = global_clock + llc_lookup_time;
                llc_busy_time += llc_lookup_time;
                tr->prev_state = tr->state;
                tr->state = EXIT;
            }
            break;
        }

            /* STATE MACHINE for MLC REPLACEMENT ends here */

        default :
            if(DEBUG) printf("ERROR: Non existant state \n");
        } /* END of SWITCH CASE FOR WRITE */

        break;
    }

    case SNOOP :
    {
        switch(tr->state)
        {

        case START :
        {
            tr->active_cp->snoops++;
            tr->prev_state = tr->state;

            int cacheindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid ;

            tr->llc_transfer_state = MLC_BUS_TRANSFER;
            tr->state = LLC_ICN_OVERFLOW;
            //tr->dst = tr->cache;
            tr->dst = cpu_network_layout[tr->cache];
            snoop_msgs++;
            tr->msg_size = CADDR_SIZE;
            tr->src = cache_network_layout[cacheindex];
            tr->timestamp += llc_transfer_time;
            if(RECORD_NOC && tr->cache != cacheindex)
                gzprintf(rec_noc_fp,"SRQ   %d %d 4 %lld\n", tr->src, tr->dst,global_clock);
            break;
        }

        case EXIT :
        {
            TRANSTYPE *parent;
            if(tr->prev_state == MLC_RSM_LLC_TRANSFER || tr->prev_state == MLC_RSM_LLC_LOOKUP)
                tr->active_cp->delete_queue_tr(tr->tr_id);
            parent = map_transaction(tr->parent);
            parent->snoop_done[tr->cpuid] = TRUE;
            if(DEBUG)
            {
                printf("FOR transaction %d\n", parent->tr_id);
                for(int i = 0; i< CORES ; i++)
                    printf("Snoop done [%d] : %d\n",i,parent->snoop_done[i]);
                parent->print();
            }
            break;
        }

        case MLC_BUS_TRANSFER :
        {
            tr->mem_queue_wait = 0;
            if(tr->active_cp->queue_empty())
            {
                tr->prev_state = tr->state;
                tr->state = MLC_LOOK_UP;
                //Measure Response time removing the trace blocking

                tr->active_cp->insert_queue(tr->tr_id);
                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;
            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = MLC_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->timestamp = BLOCKED;
            }
            break;
        }
        case MLC_QUEUED :
        {
            if(!tr->active_cp->queue_empty())
            {
                int head = tr->active_cp->queue_head();

                TRANSTYPE *head_tr = map_transaction(head);
                if(head_tr->state == MLC_BQ_OVERFLOW)
                {
                    tr->active_cp->delete_queue_tr(tr->tr_id);
                    tr->active_cp->insert_queue_after_head(tr->tr_id);
                }
            }


            if( tr->tr_id == tr->active_cp->queue_head())
            {
                tr->prev_state = tr->state;
                tr->state = MLC_LOOK_UP;
                //Measure Response time removing the trace blocking

                tr->cstate = tr->active_cp->look_up(tr->address,TRUE,tr);
                if(tr->cstate == MODIFIED)
                    tr->active_cp->hitm++;
                tr->timestamp = global_clock + mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;
            }
            break;
        }
        case LLC_ICN_OVERFLOW :
        {
            if(SHORT_CIRCUIT)
            {
                tr->state = tr->llc_transfer_state;
                tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                tr->prev_state = LLC_ICN_OVERFLOW;
                //csim_inj_msgs++;
            }
            else
            {
                if(icn_func_sim[tr->tid])
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    per_core_icn_lat[tr->tid] += SHORT_CIRCUIT_ICN_LAT;
                    per_core_icn_msgs[tr->tid] ++;
                    break;
                }

                if(tr->src == tr->dst)
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock + 1;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                }
                else if(nic_queue_full(tr->src))
                    tr->timestamp = BLOCKED;
                else
                {
                    tr->icn_trans_comp = false;
                    tr->msg_inj_time = global_clock;
                    tr->timestamp = BLOCKED;
                    insert_nic_queue(tr->src, tr->dst, tr->msg_size, global_clock, tr->tr_id);
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    tr->state = LLC_ICN_TRANSFER;
                }
            }
            break;
        }

        case LLC_ICN_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                total_icn_msgs++;
                total_icn_latency += global_clock - tr->msg_inj_time;
                //per_core_icn_lat[tr->tid] += global_clock - tr->msg_inj_time;
                //per_core_icn_msgs[tr->tid] ++;

                tr->icn_trans_comp = false;
                tr->timestamp = global_clock + 1;
                tr->prev_state = LLC_ICN_TRANSFER;
                tr->state = tr->llc_transfer_state;
            }
            break;
        }

        case MLC_LOOK_UP :
        {
            TRANSTYPE *parent;
            tr->prev_state = tr->state;
            if (tr->active_cp->delete_queue_tr(tr->tr_id)!= tr->tr_id)
                if(DEBUG) printf("ERROR: Deleting from MLC queue\n");
            int cacheindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid;

            parent = map_transaction(tr->parent);
            parent->snoop_state[tr->cpuid] = tr->active_cp->look_up(tr->address,false,tr);
            tr->llc_transfer_state = EXIT;
            tr->state = LLC_ICN_OVERFLOW;
            //tr->src = tr->cache;
            tr->src = cpu_network_layout[tr->cache];
            tr->dst = cache_network_layout[cacheindex];
            //tr->linesize = tr->active_cp->linesize/SET_SEG_SIZE;


            snoop_msgs++;
            if(tr->cstate == MODIFIED)
                tr->msg_size = CLINE_SIZE;
            else
                tr->msg_size = CADDR_SIZE;
            tr->timestamp +=  llc_transfer_time;
            if(RECORD_NOC && tr->cache != cacheindex)
                if(tr->cstate == MODIFIED)
                    gzprintf(rec_noc_fp,"SDRSP %d %d 64 %lld\n",tr->cache,cacheindex, global_clock);
                else
                    gzprintf(rec_noc_fp,"SCRSP %d %d 4 %lld\n",tr->cache,cacheindex, global_clock);


            if(parent->snoop_invalidate == TRUE || parent->type == WRITE)
            {
                if(DEBUG) printf("TRANSACTION : INVALIDATE SNOOP\n");
                tr->active_cp->invalidate_snoops++;
                tr->active_cp->change_state(tr->address,INVALID , tr);
            }
            else if(parent->type == READ)
            {
                if(tr->cstate != INVALID)
                    tr->active_cp->change_state(tr->address, SHARED, tr);
            }
            tr->active_cp= &(clevel[LLC].cache[cacheindex]);
            tr->cache = cacheindex + CORES;
            break;
        }
        }

        break;
    } /* END of SNOOP TR TYPE */

    case WRITEBACK :
    {
        switch(tr->state)
        {

        case MEM_BUS_TRANSFER :
        {
            if(tr->active_cp->queue_full())
            {
                tr->timestamp = BLOCKED;
            }
            else if(tr->active_cp->queue_empty())
            {
                tr->timestamp = global_clock +  memory_access_time;

                tr->state = EXIT;

                tr->prev_state = MEM_QUEUED;
            }
            else
            {
                tr->prev_state = tr->state;
                tr->state = MEM_QUEUED;
                tr->active_cp->insert_queue(tr->tr_id);
                tr->timestamp = BLOCKED;
            }
            break;
        }

        case MEM_QUEUED :
        {
            if(tr->tr_id == tr->active_cp->queue_head())
            {
                tr->active_cp->delete_queue_tr(tr->tr_id);
                tr->timestamp = global_clock +  memory_access_time;

                tr->state = EXIT;

                tr->prev_state = MEM_QUEUED;
            }
            break;
        }
        case EXIT :
        {
            //MEMORY->delete_queue_tr(tr->tr_id);
            int bindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid;
            clevel[LLC].cache[bindex].delete_blocked_queue(tr->tr_id);
            break;
        }
        }

        break;

    } /* END of WRITEBACK TR TYPE */

    case PREFETCH:
    {
        switch(tr->state)
        {
        case MEM_BUS_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                if(tr->active_cp->queue_full())
                {
                    if(DEBUG)
                        printf("MEM QUEUE FULL\n");
                    tr->timestamp = BLOCKED;
                }
                else if(tr->active_cp->queue_empty())
                {
                    tr->llc_first = TRUE;
                    tr->cache = CORES + (llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid);
                    tr->active_cp = &(clevel[LLC].cache[llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid]);
                    tr->prev_state = MEM_QUEUED;

                    int mem_ctr_id = DECODE_MEM_CTRLR(tr->address, tr->cpuid);
                    int cacheindex = DECODE_BANK(tr->address, tr->cpuid);
                    tr->state = MEM_ICN_OVERFLOW;
                    tr->mem_transfer_state = LLC_BLOCKED_QUEUE_HEAD;
                    tr->dst = cache_network_layout[cacheindex];
                    tr->src = mem_network_layout[mem_ctr_id];
                    tr->msg_size = CLINE_SIZE;
                    data_msgs++;
                    tr->timestamp = global_clock + memory_access_time;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = MEM_QUEUED;
                    tr->active_cp->insert_queue(tr->tr_id);
                    tr->timestamp = BLOCKED;
                }
            }
            break;
        }

        case MEM_ICN_OVERFLOW :
        {

            if(tr->src == tr->dst)
            {
                tr->state = tr->mem_transfer_state;
                tr->timestamp = global_clock + 1;
                tr->prev_state = MEM_ICN_OVERFLOW;
            }
            else if(nic_queue_full(tr->src))
            {
                if(!PF_NOC_SHORTCIRCUIT)
                    tr->timestamp = BLOCKED;
            }
            else
            {
                tr->icn_trans_comp = false;
                tr->msg_inj_time = global_clock;
                tr->timestamp = BLOCKED;
                insert_nic_queue(tr->src, tr->dst, tr->msg_size, global_clock, tr->tr_id);

                tr->prev_state = MEM_ICN_OVERFLOW;
                tr->state = MEM_ICN_TRANSFER;
            }

            break;
        }

        case MEM_ICN_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                total_icn_msgs++;
                total_icn_latency += global_clock - tr->msg_inj_time;
                per_core_icn_lat[tr->tid] += global_clock - tr->msg_inj_time;
                per_core_icn_msgs[tr->tid] ++;

                tr->icn_trans_comp = false;
                tr->timestamp = global_clock + 1;
                tr->prev_state = MEM_ICN_TRANSFER;
                tr->state = tr->mem_transfer_state;
            }
            break;
        }


        case MEM_QUEUED :
        {
            if(tr->tr_id == tr->active_cp->queue_head())
            {
                tr->active_cp->delete_queue();
                tr->timestamp = global_clock + memory_access_time;

                tr->llc_first = TRUE;
                tr->state = LLC_BLOCKED_QUEUE_HEAD;
                tr->active_cp = &(clevel[LLC].cache[DECODE_BANK(tr->address, tr->cpuid)]);
                tr->cache = CORES + (llc_shared ? DECODE_BANK(tr->address, tr->cpuid) : tr->cpuid);

                tr->prev_state = MEM_QUEUED;
            }
            break;

        }

        case LLC_BLOCKED_QUEUE_HEAD:
        {

            if(tr->llc_first)
            {
                tr->active_cp->insert_queue_after_head(tr->tr_id);
                tr->llc_first = FALSE;
                if(tr->tr_id == tr->active_cp->queue_head())
                {
                    tr->prev_state = tr->state;
                    tr->state = LLC_REPLACE_SM;
                }
                else
                {
                    tr->llcq_enter = global_clock;
                    tr->timestamp = BLOCKED;
                }
            }
            else
            {
                int head = tr->active_cp->queue_head();

                TRANSTYPE *head_tr = map_transaction(head);
                if(head_tr->state == LLC_BQ_OVERFLOW )
                {
                    tr->active_cp->queue.erase(tr->active_cp->queue.begin());
                    tr->active_cp->rq_size--;
                    tr->active_cp->insert_queue_after_head(head);
                }

                if(tr->tr_id == tr->active_cp->queue_head())
                {
                    tr->llc_queue_wait += global_clock - tr->llcq_enter;
                    tr->prev_state = tr->state;
                    tr->state = LLC_REPLACE_SM;
                }
            }
            break;
        }

        case LLC_REPLACE_SM :
        {
            int pri =0;
            /* Assumption victim lookup time inclusive of update time for the
              ** victim with new block from memory and done at same time */

            std::vector<long long> vaddr;

            //			printf("\n\n\n Place 1: Address : %d ::: RepPos: %d :::: Priority : %d ::::  Vaddress : %d :::: llcstate :%d\n",tr->address, tr->rep_pos, tr->pri, tr->vaddress, tr->llc_state);

            tr->vaddress = tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, &vaddr, tr->llc_state, tr);
            //			printf("\n\n\n Place 2: Address : %d ::: RepPos: %d :::: Priority : %d ::::  Vaddress : %d :::: llcstate :%d\n",tr->address, tr->rep_pos, tr->pri, tr->vaddress, tr->llc_state);
            tr->timestamp = global_clock + llc_victim_lookup_time + llc_lookup_time;
            tr->timestamp += tr->compaction_delay;
            llc_busy_time += llc_victim_lookup_time;
            llc_busy_time += llc_lookup_time;

            tr->prev_state = tr->state;
            tr->state = LLC_RSM_LOOKUP_COMPLETE;

            break;
        }

        case LLC_RSM_LOOKUP_COMPLETE:
        {
            int cacheindex = tr->cpuid;


            //printf("\n\n\n Place 3: Address : %d ::: RepPos: %d :::: Priority : %d ::::  Vaddress : %d :::: llcstate :%d\n",tr->address, tr->rep_pos, tr->pri, tr->vaddress, tr->llc_state);

            //Some other transaction on same address has inserted into the cache while prefetching is in process !
            if(tr->active_cp->look_up(tr->address, FALSE, tr) != INVALID)  //Address already present in some state other than invalid
            {
                total_prefetch_late++;
                //printf("\n\n\n\n\n\n\n\n\n\n  Addresss inserted while prefetching is in progress !\n");
                //printf("\nAIPP!\n");
            }
            else
                tr->active_cp->replace_victim(tr->vaddress,tr->address,EXCLUSIVE,tr->rep_pos, tr);

            tr->active_cp->prefetched_bit_set(tr->address,tr);


            //printf("\n\n\n Place 4: Address : %d ::: RepPos: %d :::: Priority : %d ::::  Vaddress : %d :::: llcstate :%d\n",tr->address, tr->rep_pos, tr->pri, tr->vaddress, tr->llc_state);

            tr->active_cp->delete_blocked_queue(tr->tr_id);
            if(tr->tr_id != tr->active_cp->delete_queue_tr(tr->tr_id))
                if(DEBUG) printf("ERROR: In deleting from Queue while LLC REPLACEMENT\n" );

            tr->prev_state = tr->state;


            /*if(HLC_PREFETCH_BUFFER)
            {
                CACHE *cp_hlc;
                cp_hlc = &(clevel[HLC].cache[tr->cpuid]);
                long long insert_address = tr->address >> cp_hlc->tag_shift;
                std::vector<long long>::iterator it;



                if (find(cp_hlc->prefetch_buffer.begin(), cp_hlc->prefetch_buffer.end(), (insert_address)) == cp_hlc->prefetch_buffer.end())
                {	// Address not already in HLC prefetch_buffer
                    it = cp_hlc->prefetch_buffer.begin();
                    cp_hlc->prefetch_buffer.insert(it, insert_address);
                }

                if (cp_hlc->prefetch_buffer.size() >= 163840)
                    cp_hlc->prefetch_buffer.resize(163840);
            }*/

            //if rank 2,3,4
            if(push_to_l1_rank1 == 0)
            {
                transaction_commit(tr);
                tr->state = EXIT;
            }//else//
            else if(push_to_l1_rank1 == 1)
            {
                int TrPriority = -1;
                if(APP_PRIOR)
                    TrPriority = FindAppPriority(tr);

                if(TrPriority == 4)
                {
                    //printf("\n  Going inside!!");
                    tr->state = LLC_ICN_OVERFLOW;
                    tr->llc_transfer_state = MLC_RESPONSE_TRANSFER;
                    tr->active_cp = &(clevel[MLC].cache[cacheindex]);
                    tr->src = cache_network_layout[tr->cache - CORES];
                    tr->msg_size = CLINE_SIZE;
                    data_msgs++;
                    tr->dst = cpu_network_layout[tr->cpuid];
                    tr->timestamp += llc_transfer_time;
                    tr->cache = cacheindex;
                }
                else{
                    //printf("\n  Tr_prrior : %d \n!!",TrPriority);
                }
            }

            break;
        }

            //Prefetch to L1 cache.

        case LLC_ICN_OVERFLOW :
        {
            if(SHORT_CIRCUIT)
            {
                tr->state = tr->llc_transfer_state;
                tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                tr->prev_state = LLC_ICN_OVERFLOW;
                //csim_inj_msgs++;
            }
            else
            {
                if(icn_func_sim[tr->tid])
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock+SHORT_CIRCUIT_ICN_LAT;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    per_core_icn_lat[tr->tid] += SHORT_CIRCUIT_ICN_LAT;
                    per_core_icn_msgs[tr->tid] ++;
                    break;
                }

                if(tr->src == tr->dst)
                {
                    tr->state = tr->llc_transfer_state;
                    tr->timestamp = global_clock + 1;
                    tr->prev_state = LLC_ICN_OVERFLOW;
                }
                else if(nic_queue_full(tr->src))
                    tr->timestamp = BLOCKED;
                else
                {
                    tr->icn_trans_comp = false;
                    tr->msg_inj_time = global_clock;

                    tr->timestamp = BLOCKED;
                    insert_nic_queue(tr->src, tr->dst, tr->msg_size, global_clock, tr->tr_id);
                    tr->prev_state = LLC_ICN_OVERFLOW;
                    tr->state = LLC_ICN_TRANSFER;
                }
            }
            break;
        }

        case LLC_ICN_TRANSFER :
        {
            if(tr->icn_trans_comp)
            {
                total_icn_msgs++;
                total_icn_latency += global_clock - tr->msg_inj_time;
                per_core_icn_lat[tr->tid] += global_clock - tr->msg_inj_time;
                per_core_icn_msgs[tr->tid] ++;

                tr->icn_trans_comp = false;
                tr->timestamp = global_clock + 1;
                tr->prev_state = LLC_ICN_TRANSFER;
                tr->state = tr->llc_transfer_state;
            }
            break;
        }

            /* STATE MACHINE for MLC REPLACEMENT begins here */
        case MLC_RESPONSE_TRANSFER :
        {
            tr->active_cp->insert_queue_after_head(tr->tr_id);
            if(tr->active_cp->queue_head() == tr->tr_id)
            {
                tr->timestamp += core_transfer_time;
                transaction_commit(tr);
                tr->timestamp -= core_transfer_time;

                if(tr->active_cp->look_up(tr->address, false,tr) == SHARED)
                {
                    tr->active_cp->change_state(tr->address,tr->mlc_state, tr);
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                    break;
                }
                tr->vaddress = tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, NULL, INVALID, tr);
                if(tr->vaddress != tr->address)
                    tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);
                else tr->vstate = INVALID;
                tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->mlc_state,tr->rep_pos, tr);


                //if(l1prefetch_enable == 1)
                //if(tr->prefetch_transaction == 1)
                //tr->active_cp->prefetched_bit_set(tr->address,tr);



                tr->timestamp += mlc_victim_lookup_time;
                mlc_busy_time += mlc_victim_lookup_time;
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;

                if(INVALID == tr->vstate || SHARED == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_REPLACE_SM;
                }
            }
            else
            {
                tr->timestamp = BLOCKED;
                tr->prev_state = tr->state;
                tr->state = MLC_BLOCKED_HEAD_QUEUE;
            }
            break;
        }
        case MLC_BLOCKED_HEAD_QUEUE:
        {
            int head = tr->active_cp->queue_head();

            TRANSTYPE *head_tr = map_transaction(head);
            if(head_tr->state == MLC_BQ_OVERFLOW)
            {
                tr->active_cp->queue.erase(tr->active_cp->queue.begin());
                tr->active_cp->rq_size--;
                tr->active_cp->insert_queue_after_head(head);
            }

            if(tr->active_cp->queue_head() == tr->tr_id)
            {
                tr->timestamp = global_clock + core_transfer_time;
                transaction_commit(tr);
                tr->timestamp -= core_transfer_time;
                if(tr->active_cp->look_up(tr->address, false,tr) == SHARED)
                {
                    tr->active_cp->change_state(tr->address,tr->mlc_state,tr);
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                    break;
                }

                tr->vaddress = tr->active_cp->victim_lookup(tr->address, &tr->rep_pos, NULL, INVALID, tr);
                tr->active_cp->replace_victim(tr->vaddress,tr->address,tr->mlc_state,tr->rep_pos, tr);
                tr->vstate = tr->active_cp->look_up(tr->vaddress,FALSE,tr);

                tr->timestamp = global_clock + mlc_victim_lookup_time;
                mlc_busy_time += mlc_victim_lookup_time;
                tr->timestamp += mlc_lookup_time;
                mlc_busy_time += mlc_lookup_time;

                if(INVALID == tr->vstate || SHARED == tr->vstate || EXCLUSIVE == tr->vstate)
                {
                    tr->prev_state = tr->state;
                    tr->state = EXIT;
                }
                else
                {
                    tr->prev_state = tr->state;
                    tr->state = MLC_REPLACE_SM;
                }
            }

            break;
        }
        case MLC_REPLACE_SM :
        {
            int cacheindex = llc_shared ? DECODE_BANK(tr->vaddress,tr->cpuid): tr->cpuid;

            int bindex = llc_shared ? DECODE_BANK(tr->address, tr->cpuid): tr->cpuid;
            clevel[LLC].cache[bindex].delete_blocked_queue(tr->tr_id);
            tr->active_cp->writebacks++;
            tr->active_cp->delete_queue_tr(tr->tr_id);
            tr->active_cp->delete_blocked_queue(tr->tr_id);

            tr->active_cp = &(clevel[LLC].cache[cacheindex]);
            tr->prev_state = tr->state;
            tr->llc_transfer_state = MLC_RSM_LLC_TRANSFER;
            tr->state = LLC_ICN_OVERFLOW;
            //tr->src = tr->cache;
            tr->src = cpu_network_layout[tr->cpuid];
            tr->msg_size = (fetch_csize(tr->vdata)*SET_SEG_SIZE)/FLIT_SIZE_BYTES + CADDR_SIZE;
            wb_msgs++;
            tr->dst = cache_network_layout[cacheindex];
            tr->timestamp += llc_transfer_time;
            if(RECORD_NOC && tr->cache != cacheindex)
                gzprintf(rec_noc_fp,"WBX   %d %d 64 %lld\n", tr->cache,cacheindex, global_clock);
            tr->cache = cacheindex + CORES;
            break;
        }

        case MLC_RSM_LLC_TRANSFER :
        {
            if(EXCLUSIVE == tr->vstate)
                tr->llc_state = INVALID;
            else if(MODIFIED == tr->vstate)
                tr->llc_state = MODIFIED;

            if(tr->active_cp->queue_empty())
            {

                tr->active_cp->insert_queue(tr->tr_id);
                tr->active_cp->change_state(tr->vaddress,tr->llc_state, tr);
                
                tr->timestamp += llc_lookup_time;
                llc_busy_time += llc_lookup_time;
                tr->prev_state = tr->state;
                tr->state = EXIT;
            }
            else
            {
                tr->active_cp->insert_queue(tr->tr_id);
                tr->timestamp = BLOCKED;
                tr->prev_state = tr->state;
                tr->state = MLC_RSM_LLC_LOOKUP;
            }
            break;
        }
        case MLC_RSM_LLC_LOOKUP :
        {
            if(tr->active_cp->queue_head() == tr->tr_id)
            {

                tr->active_cp->change_state(tr->vaddress,tr->llc_state, tr);


                tr->timestamp = global_clock + llc_lookup_time;
                llc_busy_time += llc_lookup_time;
                tr->prev_state = tr->state;
                tr->state = EXIT;
            }
            break;
        }

            /* STATE MACHINE for MLC REPLACEMENT ends here */


        case EXIT :
        {
            break;
        }
        }

        break;
    } /* END of PREFETCH TR TYPE */


    }/* END of switch(type) */

    //if(DEBUG)
    {
        history_entry_t m;
        m.state = tr->state;
        m.timestamp = global_clock;//tr->timestamp;
        if(tr->history.size())
        {
            if(tr->state != tr->history[tr->history.size()-1].state)
                //tr->history.push_back(tr->state);
                tr->history.push_back(m);
        }
        else
            tr->history.push_back(m);
    }
    if(tr->tr_id == DBG_TRID)
    {
        DEBUG = 0;
    }
    if(tr != map_transaction(tr->tr_id))
    {
        printf("ERR TR pool being modified for transaction at end!!! %d\n",tr->tr_id);
        tr->print();
        tr->hist();
    }
}

void insert_into_HLC(long long address, int cpuid, int read_or_write)
{

    TRANSTYPE *tr;
    CACHE *cp_hlc;
    cp_hlc = &(clevel[HLC].cache[cpuid]);

    //Insert into HLC
    //tr->active_cp->change_state(tr->address,tr->mlc_state,tr);
    //tr->cstate = tr->active_cp->look_up(tr->address,FALSE,tr);

    numrefs_for_repl++; // LRU
    if(cp_hlc->func_look_up(address,FALSE) == INVALID)
    {
        cp_hlc->refs_per_core[cpuid]++;
        int rep_pos;
        long long vaddress = cp_hlc->victim_lookup(address, &rep_pos, NULL, INVALID, tr);
        cp_hlc->replace_victim(vaddress,address,SHARED,rep_pos, tr);
    }
}

void transaction_commit(TRANSTYPE *tr)
{
    char types[20];
    char buffer[100];
    long long diff;

    //insert_into_HLC(tr->address, tr->cpuid, tr->type);
    tr_commited++;

    if(!(tr_commited %10000000))
        transaction_count =0;


    if(STAT)
    {
        if(!(tr_commited %100000))
        {
            print_data_sharing();
            print_stats();
#if !SHORT_CIRCUIT
            sim_result();
            printf("Total Ejected  msgs     : %lld\nAverage Network Latency : %.2f\nAvg. queue delay        : %.2f \n",total_icn_msgs, total_icn_latency/(float)total_icn_msgs, total_csim_nic_qdelay/(float)total_icn_msgs);
#endif
            printf("Executed References     : %lld\n",tr_commited);
        }
    }

    diff =  (global_clock - tr->enter_time);
    total_resp_time += diff;
    llc_queue_wait += tr->llc_queue_wait;
    mlc_queue_wait += tr->mlc_queue_wait;
    mem_queue_wait[tr->cpuid] += tr->mem_queue_wait;
    snoop_wait += tr->snoop_wait;

    if(tr->mem_queue_wait > 5000  && tr->type == PREFETCH)
    {
        printf("\nBOMB############################################################################################");
        //  print_data_sharing();
        //  print_stats();
        //  sim_result();

        printf("\nTotal Ejected  msgs     : %lld\nAverage Network Latency : %.2f\nAvg. queue delay        : %.2f \n",total_icn_msgs, total_icn_latency/(float)total_icn_msgs, total_csim_nic_qdelay/(float)total_icn_msgs);
        printf("Executed References     : %lld\n",tr_commited);

        printf("\nL1Miss: %hd",tr->l1miss);
        printf("\nL2Miss: %d",tr->l2miss);
        printf("\nL2Hit: %d",tr->l2hit);
        printf("\nTotal_Instructions_time: %lld",diff);
        //  printf("\nTotal_resp_time: %d",total_resp_time);
        printf("\nllc_queue_wait: %lld",tr->llc_queue_wait);
        printf("\nmlc_queue_wait: %lld",tr->mlc_queue_wait);
        printf("\nmem_queue_wait: %lld",tr->mem_queue_wait);
        printf("\npf_transaction: %d",tr->prefetch_transaction);

        printf("\nTYPE : %d ::: TR_ID : %d",tr->type, tr->tr_id);
        printf("\nenter_time: %d",tr->enter_time);
        printf("\nmem_queue_enter_time: %d",tr->memq_enter);

        printf("\n\nsnoop_wait: %lld",tr->snoop_wait);

        //printf("\nTime_In_Network: %d",tr->time_in_network);
    }



    if(DEBUG)
        printf("TRANSACTION:committing Transaction :%lld, at time %lld\n ",tr->tr_id, tr->timestamp);

    switch(tr->type)
    {
    case READ: strcpy(types,"READ"); break;
    case WRITE: strcpy(types,"WRITE"); break;
    case SNOOP: strcpy(types,"SNOOP"); break;
    case WRITEBACK: strcpy(types,"WRITEBACK"); break;
    case PREFETCH: strcpy(types,"PREFETCH"); break;
    case NETWORK: strcpy(types,"NETWORK"); break;
    case SIMPLE: strcpy(types,"SIMPLE"); break;
    default : strcpy(types,"@@ERR");
    }

    if(tr->mem_queue_wait > 10000)
        //if(tr->timestamp < global_clock - 100)
    {
        printf("ERR: in committing clock :%lld timestamp:%lld for transaction:%lld\n",global_clock, tr->timestamp,tr->tr_id);
        tr->hist();
        tr->print();
        if(DEBUG)
            getchar();
    }

#if SC_INTEG

    if(refs[tr->tid] == 0)
    {
        if(DEBUG)
        {
            printf("FATAL ERR, commiting more instrs after thread done for thread %d\n",tr->tid);
            tr->hist();
            tr->print();
            getchar();
        }
    }
    else
    {
        commit_refs[tr->tid]++;

        if(commit_refs[tr->tid] == refs[tr->tid])
        {
            thread_done[tr->tid] = true;
            refs[tr->tid] = 0;
            commit_refs[tr->tid] = 0;

            for(int i = 0; i< thread_per_proc*numcpus; i++)
                if(commit_refs[i]/(float)refs[i] > 0.85 )
                {
                    thread_done[i] = true;
                    refs[i] -= commit_refs[i];
                    commit_refs[i]=0;
                }
            end_sim = true;
        }
    }
#endif
    if(RECORD)
    {
        gzprintf(out_fp, "%8s %8llx %2d %8ld ", types, tr->address, tr->cpuid, diff);
        gzflush(out_fp, 0);
        gzprintf(out_fp,"%8d ",   tr->mlc_queue_wait);
        gzflush(out_fp, 0);
        gzprintf(out_fp,"%8d ",   tr->llc_queue_wait);
        gzflush(out_fp, 0);
        gzprintf(out_fp,"%8d\n",  tr->snoop_wait);
        gzflush(out_fp, 0);
    }
}
void TRANSTYPE::hist()
{
    for( int i=0; i<history.size(); i++)
        printf("%s %lld\n",string_tr[history[i].state], history[i].timestamp);
}


/*PRINT*/
void
TRANSTYPE::print() {

    char str[30];
    char types[10];
    char caches[10];

    switch(type)
    {
    case READ: strcpy(types , "READ"); break;
    case WRITE: strcpy(types , "WRITE"); break;
    case SNOOP: strcpy(types, "SNOOP"); break;
    case WRITEBACK: strcpy(types, "WRITEBACK"); break;
    case PREFETCH: strcpy(types, "PREFETCH"); break;
    case NETWORK: strcpy(types, "NETWORK"); break;
    case SIMPLE: strcpy(types,"SIMPLE"); break;
    default : strcpy(types, "@@ERR");
    }

    printf("<tr_id = %lld,", tr_id );
    fflush(stdout);
    if(type == SNOOP)
        printf("pid = %lld,", parent );
    fflush(stdout);
    printf("state = %s,", string_tr[state]);
    fflush(stdout);
    printf(" type = %s, address = %lx, ",types, address);
    fflush(stdout);
    printf("cpuid = %d mem_id = %d",cpuid,mem_op_id);
    fflush(stdout);
    printf(",tid= %d, timestamp = %lld,",tid, timestamp);
    // if(state == START)
    // printf(" cache = MLC%d >\n",cpuid);
    // else
    printf(" cache = %s", active_cp->clabel);
    printf(", PF_TR = %d>\n", prefetch_transaction);
    fflush(stdout);
}



#define INTR 100000

double update_state(long long address, int cpuid, int read_or_write, long long data[16])
{
    double penalty=0;
    CACHE *cp_mlc;
    CACHE *cp_llc, *cp_vllc;

    int mlc_cstate, llc_cstate, mlc_vstate, llc_vstate;
    int mlc_nstate, llc_nstate, dummy_vstate;
    int cacheindex,vindex;
    long long mlc_vaddress=-1, llc_vaddress = -1, dummy_vaddr=-1;

    int mem_ctr_id, vmem_ctr_id;
    bool l1miss = false, l2miss=false, l1wbx= false, l2wbx = false;


    numrefs_for_repl++;
    cacheindex = DECODE_BANK(address,cpuid);
    mem_ctr_id = mem_network_layout[DECODE_MEM_CTRLR(address, cpuid)];

    //FIXME hardcoded for 8x8 mesh with 4x4 clusters
    int cluster_id = ((cacheindex/8)/4)*2 + (cacheindex%8)/4;

    //Debug Stuff
    /*unsigned set_shift = clevel[LLC].cache[0].set_shift;
    unsigned set_mask = clevel[LLC].cache[0].set_mask;
    unsigned level = LLC;

    static FILE *fp_dump;
    static bool first = true;
    if(first)
    {
    fp_dump = fopen("tmp_dump1", "w");
    printf("shifts %d %d %d mask:%llx %llx %llx\n",addr1_shift, addr2_shift,set_shift,addr1_mask,addr2_mask,set_mask);
    first=false;
  //exit(1);
  }
  if(cpuid == 0)
  fprintf(fp_dump,"%llx %d %x\n" ,address,DECODE_SET(address),DECODE_SET(address));*/

    cp_mlc = &(clevel[MLC].cache[cpuid]);
    cp_llc = &(clevel[LLC].cache[cacheindex]);
    mlc_cstate = cp_mlc->func_look_up(address,TRUE);

    penalty += 2*core_transfer_time + mlc_lookup_time;

    assert(cacheindex<num_llc_banks);

    // Read SM
    if(read_or_write)
    {
        if(mlc_cstate == INVALID)
        {
            penalty += 2*llc_transfer_time + llc_lookup_time;
            processor[cpuid].l1misses++;
            l1miss = true;
            processor[cpuid].bank_touch[cacheindex]++;
            processor[cpuid].per_flow_packets[cluster_id]++;
            //printf("src_PE P%d --> dst_PE C%d [%llx] \n",cpuid,cacheindex, address);

            llc_cstate = cp_llc->func_look_up(address,TRUE);
            if(llc_cstate == MODIFIED || llc_cstate == INVALID)
            {
                llc_nstate = EXCLUSIVE;
                mlc_nstate = EXCLUSIVE;
                if(llc_cstate == INVALID)
                {
                    processor[cpuid].l2misses++;
                    l2miss = true;
                    penalty += mem_transfer_time + memory_access_time;
                }
            }
            else if(llc_cstate == EXCLUSIVE || llc_cstate == SHARED)
            {
                // Change state of other owner to shared
                llc_nstate = SHARED;
                mlc_nstate = SHARED;
                for (int i =0; i < CORES  ; i++)
                    if(i == cpuid)
                        continue;
                    else
                        clevel[MLC].cache[i].func_change_state(address,SHARED,&dummy_vaddr, &dummy_vstate,data);
            }
            cp_llc->func_change_state(address,llc_nstate,&llc_vaddress,&llc_vstate,data);
            cp_mlc->func_change_state(address,mlc_nstate,&mlc_vaddress,&mlc_vstate,data);
        }// else mlc state E,M,S no change hit in mlc

    } // End of Read SM
    else
    {
        // change llc state to -->E and All sharers -->I mlc state S-->M
        if(mlc_cstate == INVALID)
        {
            penalty += 2*llc_transfer_time + llc_lookup_time;
            //processor[cpuid].l1misses++;
            l1miss = true;
            processor[cpuid].bank_touch[cacheindex]++;
            processor[cpuid].per_flow_packets[cluster_id]++;
            //printf("src_PE P%d --> dst_PE C%d [%llx]\n",cpuid,cacheindex,address);

            mlc_nstate = MODIFIED;
            llc_nstate = EXCLUSIVE;
            llc_cstate = cp_llc->func_look_up(address,TRUE);
            if(llc_cstate == EXCLUSIVE || llc_cstate == SHARED)
            {
                // Change state of other sharers to invalid
                for (int i =0; i < CORES  ; i++)
                    if(i == cpuid)
                        continue;
                    else
                        clevel[MLC].cache[i].func_change_state(address,INVALID,&dummy_vaddr, &dummy_vstate,data);
            }
            if(llc_cstate == INVALID)
            {
                processor[cpuid].l2misses++;
                l2miss = true;
                penalty += mem_transfer_time + memory_access_time;
            }
            cp_llc->func_change_state(address,llc_nstate,&llc_vaddress,&llc_vstate,data);
            cp_mlc->func_change_state(address,mlc_nstate,&mlc_vaddress,&mlc_vstate,data);
        }
        // no to change llc state mlc state S-->M
        else if(mlc_cstate == EXCLUSIVE)
        {
            mlc_nstate = MODIFIED;
            cp_mlc->func_change_state(address,mlc_nstate,&mlc_vaddress,&mlc_vstate,data);
        }
        // change llc state to S-->E and All sharers -->I mlc state S-->M
        else if(mlc_cstate == SHARED)
        {
            mlc_nstate = MODIFIED;
            llc_nstate = EXCLUSIVE;
            // Change state of other sharers to invalid
            for (int i =0; i < CORES  ; i++)
                if(i == cpuid)
                    continue;
                else
                    clevel[MLC].cache[i].func_change_state(address,INVALID,&dummy_vaddr, &dummy_vstate,data);
            cp_llc->func_change_state(address,llc_nstate,&llc_vaddress,&llc_vstate,data);
            cp_mlc->func_change_state(address,mlc_nstate,&mlc_vaddress,&mlc_vstate,data);
        }
        // else mlc state is M no change hit in mlc
    } // End of write SM

    // mlc replacement SM
    if(mlc_vaddress != -1)
    {
        if(mlc_vstate == MODIFIED)
        {
            l1wbx = true;
            vindex = DECODE_BANK(mlc_vaddress,cpuid);//mlc_vaddress>>tag_shift) & (num_llc_banks-1);
            cp_vllc = &(clevel[LLC].cache[vindex]);
            cp_vllc->func_change_state(mlc_vaddress,MODIFIED,&dummy_vaddr,&dummy_vstate,data);
        }
    }
    // llc replacement SM
    if(llc_vaddress != -1)
    {
        vmem_ctr_id = mem_network_layout[DECODE_MEM_CTRLR(llc_vaddress, cpuid)];
        l2wbx = true;
        if(llc_vstate == EXCLUSIVE || llc_vstate == SHARED)
        {
            for (int i =0; i < CORES  ; i++)
                if(i == cpuid)
                    continue;
                else
                    clevel[MLC].cache[i].func_change_state(address,INVALID,&dummy_vaddr, &dummy_vstate,data);

        }
    }
    if(l1miss && processor[cpuid].record_trace_fp != NULL && processor[cpuid].network_trace_mode == true)
        gzprintf(processor[cpuid].record_trace_fp,"MNET %2d %2d %2d %2d\n",cacheindex, l2miss ? mem_ctr_id : - 1, l1wbx ? vindex : -1 , l2wbx ? vmem_ctr_id : -1);
    return penalty;
}

bool determinel1miss(long long address, int cpuid, int read_or_write)
{

    if(numclevels == 3)
    {
        //printf("\n Determine L1 miss : ADD = %lld,   CPUID = %d,   RW = %d ",address, cpuid, read_or_write);
        CACHE *cp_hlc;
        int hlc_cstate;
        bool miss = false;

        numrefs_for_repl++; // LRU

        cp_hlc = &(clevel[HLC].cache[cpuid]);
        hlc_cstate = cp_hlc->func_look_up(address,TRUE);
        clevel[HLC].cache[cpuid].refs++;

        if(hlc_cstate != INVALID)
        {
            cp_hlc->refs_per_core[cpuid]++;
            if(DEBUG)
            {
                printf("\n Returning miss value as %d\n", miss);
                getchar();
            }
        }

        if(HLC_PREFETCH_BUFFER)
        {

            vector<long long>::iterator it;
            it = find(cp_hlc->prefetch_buffer.begin(), cp_hlc->prefetch_buffer.end(), (address >> cp_hlc->tag_shift) );

            //printf("\n Finding : %lld %lld  %lld ", (address >> cp_hlc->tag_shift), address, cp_hlc->tag_shift);

            if ( it != cp_hlc->prefetch_buffer.end())
            {

                if(DEBUG)
                {
                    printf("Prefetch Buffer Hit");
                    getchar();
                }


                //printf("\n Prefetch buffer hit \n");
                // Address found in the HLC prefetch_buffer
                HLC_PB_hit++;		// increment the prefetch hit statistics
                cp_hlc->prefetch_buffer.erase(it);		//remove from the prefetch buffer, as it's hit once.
                //now, proceed as usual to insert that address into the HLC cache.
                hlc_cstate = SHARED;

                TRANSTYPE *tr;
                //Insert into HLC
                if(cp_hlc->look_up(address,FALSE,tr) == INVALID)
                {
                    if(DEBUG)
                    {
                        printf("Data not found in L1. So, inserting.");
                        getchar();
                    }
                    int rep_pos;
                    //long long vaddress = cp_hlc->victim_lookup(address, &rep_pos, NULL, INVALID, tr);
                    //cp_hlc->replace_victim(vaddress,address,SHARED,rep_pos, tr);
                }
                else
                {
                    if(DEBUG)
                    {
                        printf("\n Did not put into the cache! Line not in INVALID state.\n");
                        getchar();
                    }
                }
            }
        }
        else if (hlc_cstate == INVALID)
        {
            miss = true;
            numrefs_for_repl--; // LRU (no need to increment numrefs_for_repl)
            clevel[HLC].cache[cpuid].misses++;
        }
        return miss;
    }

    {    //    else if(numclevels = 2)
        //    {
        //        CACHE *cp_mlc;

        //         int mlc_cstate, mlc_vstate;
        //         int mlc_nstate, dummy_vstate;
        //         long long mlc_vaddress=-1, llc_vaddress = -1, dummy_vaddr=-1;
        //         long long data[16];

        //         bool miss = false;

        //         numrefs_for_repl++;

        //         cp_mlc = &(clevel[MLC].cache[cpuid]);
        //         mlc_cstate = cp_mlc->func_look_up(address,FALSE);

        //         // Read SM
        //         if(read_or_write)
        //         {
        //           if(mlc_cstate == INVALID)
        //             miss = true;
        //         } // End of Read SM
        //         else
        //         {
        //           // change llc state to -->E and All sharers -->I mlc state S-->M
        //           if(mlc_cstate == INVALID)
        //             miss = true;
        //           // no to change llc state mlc state S-->M
        //           else if(mlc_cstate == EXCLUSIVE)
        //           {
        //             mlc_nstate = MODIFIED;
        //             cp_mlc->func_change_state(address,mlc_nstate,&mlc_vaddress,&mlc_vstate,data);
        //           }
        //           // change llc state to S-->E and All sharers -->I mlc state S-->M
        //           else if(mlc_cstate == SHARED)
        //             miss = true;
        //           // else mlc state is M no change hit in mlc
        //         } // End of write SM

        //         if(miss)
        //           numrefs_for_repl--;
        //         else
        //           cp_mlc->func_look_up(address,TRUE);

        //         return miss;
        //    }
    }
}
